prism 0.21.0 → 0.23.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 +40 -1
- data/README.md +2 -1
- data/docs/releasing.md +84 -16
- data/docs/ruby_parser_translation.md +19 -0
- data/docs/serialization.md +2 -0
- data/ext/prism/api_node.c +784 -785
- data/ext/prism/extension.c +56 -19
- data/ext/prism/extension.h +2 -2
- data/include/prism/diagnostic.h +11 -6
- data/include/prism/encoding.h +7 -0
- data/include/prism/util/pm_constant_pool.h +1 -1
- data/include/prism/util/pm_strpbrk.h +4 -1
- data/include/prism/version.h +2 -2
- data/lib/prism/ffi.rb +8 -3
- data/lib/prism/lex_compat.rb +17 -1
- data/lib/prism/node.rb +212 -32
- data/lib/prism/node_ext.rb +25 -2
- data/lib/prism/parse_result.rb +46 -16
- data/lib/prism/serialize.rb +14 -6
- data/lib/prism/translation/parser/compiler.rb +16 -6
- data/lib/prism/translation/parser.rb +19 -12
- data/lib/prism/translation/ripper.rb +577 -0
- data/lib/prism/translation/ruby_parser.rb +1521 -0
- data/lib/prism/translation.rb +3 -3
- data/lib/prism.rb +0 -1
- data/prism.gemspec +5 -3
- data/src/diagnostic.c +20 -15
- data/src/encoding.c +16 -17
- data/src/options.c +7 -2
- data/src/prism.c +145 -90
- data/src/serialize.c +24 -13
- data/src/token_type.c +3 -3
- data/src/util/pm_constant_pool.c +1 -1
- data/src/util/pm_string.c +0 -7
- data/src/util/pm_strpbrk.c +122 -14
- metadata +6 -4
- data/lib/prism/ripper_compat.rb +0 -207
data/src/prism.c
CHANGED
@@ -492,7 +492,8 @@ pm_parser_err(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, pm_
|
|
492
492
|
/**
|
493
493
|
* Append an error to the list of errors on the parser using a format string.
|
494
494
|
*/
|
495
|
-
#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...)
|
495
|
+
#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
|
496
|
+
pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
|
496
497
|
|
497
498
|
/**
|
498
499
|
* Append an error to the list of errors on the parser using the location of the
|
@@ -507,7 +508,8 @@ pm_parser_err_current(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
|
|
507
508
|
* Append an error to the list of errors on the parser using the given location
|
508
509
|
* using a format string.
|
509
510
|
*/
|
510
|
-
#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...)
|
511
|
+
#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
|
512
|
+
PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
|
511
513
|
|
512
514
|
/**
|
513
515
|
* Append an error to the list of errors on the parser using the location of the
|
@@ -522,7 +524,15 @@ pm_parser_err_node(pm_parser_t *parser, const pm_node_t *node, pm_diagnostic_id_
|
|
522
524
|
* Append an error to the list of errors on the parser using the location of the
|
523
525
|
* given node and a format string.
|
524
526
|
*/
|
525
|
-
#define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...)
|
527
|
+
#define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) \
|
528
|
+
PM_PARSER_ERR_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
|
529
|
+
|
530
|
+
/**
|
531
|
+
* Append an error to the list of errors on the parser using the location of the
|
532
|
+
* given node and a format string, and add on the content of the node.
|
533
|
+
*/
|
534
|
+
#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, diag_id) \
|
535
|
+
PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, (int) ((node)->location.end - (node)->location.start), (const char *) (node)->location.start)
|
526
536
|
|
527
537
|
/**
|
528
538
|
* Append an error to the list of errors on the parser using the location of the
|
@@ -546,7 +556,15 @@ pm_parser_err_token(pm_parser_t *parser, const pm_token_t *token, pm_diagnostic_
|
|
546
556
|
* Append an error to the list of errors on the parser using the location of the
|
547
557
|
* given token and a format string.
|
548
558
|
*/
|
549
|
-
#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...)
|
559
|
+
#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) \
|
560
|
+
PM_PARSER_ERR_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
|
561
|
+
|
562
|
+
/**
|
563
|
+
* Append an error to the list of errors on the parser using the location of the
|
564
|
+
* given token and a format string, and add on the content of the token.
|
565
|
+
*/
|
566
|
+
#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
|
567
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
|
550
568
|
|
551
569
|
/**
|
552
570
|
* Append a warning to the list of warnings on the parser.
|
@@ -2890,7 +2908,8 @@ pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
|
|
2890
2908
|
static pm_def_node_t *
|
2891
2909
|
pm_def_node_create(
|
2892
2910
|
pm_parser_t *parser,
|
2893
|
-
|
2911
|
+
pm_constant_id_t name,
|
2912
|
+
const pm_token_t *name_loc,
|
2894
2913
|
pm_node_t *receiver,
|
2895
2914
|
pm_parameters_node_t *parameters,
|
2896
2915
|
pm_node_t *body,
|
@@ -2920,8 +2939,8 @@ pm_def_node_create(
|
|
2920
2939
|
.type = PM_DEF_NODE,
|
2921
2940
|
.location = { .start = def_keyword->start, .end = end },
|
2922
2941
|
},
|
2923
|
-
.name =
|
2924
|
-
.name_loc = PM_LOCATION_TOKEN_VALUE(
|
2942
|
+
.name = name,
|
2943
|
+
.name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
|
2925
2944
|
.receiver = receiver,
|
2926
2945
|
.parameters = parameters,
|
2927
2946
|
.body = body,
|
@@ -4642,13 +4661,20 @@ pm_multi_target_node_create(pm_parser_t *parser) {
|
|
4642
4661
|
*/
|
4643
4662
|
static void
|
4644
4663
|
pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
|
4645
|
-
if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)
|
4664
|
+
if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
|
4646
4665
|
if (node->rest == NULL) {
|
4647
4666
|
node->rest = target;
|
4648
4667
|
} else {
|
4649
4668
|
pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
|
4650
4669
|
pm_node_list_append(&node->rights, target);
|
4651
4670
|
}
|
4671
|
+
} else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
|
4672
|
+
if (node->rest == NULL) {
|
4673
|
+
node->rest = target;
|
4674
|
+
} else {
|
4675
|
+
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
|
4676
|
+
pm_node_list_append(&node->rights, target);
|
4677
|
+
}
|
4652
4678
|
} else if (node->rest == NULL) {
|
4653
4679
|
pm_node_list_append(&node->lefts, target);
|
4654
4680
|
} else {
|
@@ -7172,7 +7198,7 @@ lex_numeric(pm_parser_t *parser) {
|
|
7172
7198
|
static pm_token_type_t
|
7173
7199
|
lex_global_variable(pm_parser_t *parser) {
|
7174
7200
|
if (parser->current.end >= parser->end) {
|
7175
|
-
|
7201
|
+
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_INVALID_VARIABLE_GLOBAL);
|
7176
7202
|
return PM_TOKEN_GLOBAL_VARIABLE;
|
7177
7203
|
}
|
7178
7204
|
|
@@ -7213,7 +7239,7 @@ lex_global_variable(pm_parser_t *parser) {
|
|
7213
7239
|
} while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0);
|
7214
7240
|
|
7215
7241
|
// $0 isn't allowed to be followed by anything.
|
7216
|
-
|
7242
|
+
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_INVALID_VARIABLE_GLOBAL);
|
7217
7243
|
}
|
7218
7244
|
|
7219
7245
|
return PM_TOKEN_GLOBAL_VARIABLE;
|
@@ -7244,7 +7270,7 @@ lex_global_variable(pm_parser_t *parser) {
|
|
7244
7270
|
} else {
|
7245
7271
|
// If we get here, then we have a $ followed by something that isn't
|
7246
7272
|
// recognized as a global variable.
|
7247
|
-
|
7273
|
+
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_INVALID_VARIABLE_GLOBAL);
|
7248
7274
|
}
|
7249
7275
|
|
7250
7276
|
return PM_TOKEN_GLOBAL_VARIABLE;
|
@@ -8148,10 +8174,10 @@ lex_at_variable(pm_parser_t *parser) {
|
|
8148
8174
|
while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0) {
|
8149
8175
|
parser->current.end += width;
|
8150
8176
|
}
|
8151
|
-
} else if (type == PM_TOKEN_CLASS_VARIABLE) {
|
8152
|
-
pm_parser_err_current(parser, PM_ERR_INCOMPLETE_VARIABLE_CLASS);
|
8153
8177
|
} else {
|
8154
|
-
|
8178
|
+
pm_diagnostic_id_t diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
|
8179
|
+
size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
|
8180
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, diag_id, (int) ((parser->current.end + width) - parser->current.start), (const char *) parser->current.start);
|
8155
8181
|
}
|
8156
8182
|
|
8157
8183
|
// If we're lexing an embedded variable, then we need to pop back into the
|
@@ -9590,11 +9616,21 @@ parser_lex(pm_parser_t *parser) {
|
|
9590
9616
|
if (*parser->current.start != '_') {
|
9591
9617
|
size_t width = char_is_identifier_start(parser, parser->current.start);
|
9592
9618
|
|
9593
|
-
// If this isn't the beginning of an identifier, then
|
9594
|
-
// token as we've exhausted all of the
|
9595
|
-
// it and return the next
|
9619
|
+
// If this isn't the beginning of an identifier, then
|
9620
|
+
// it's an invalid token as we've exhausted all of the
|
9621
|
+
// other options. We'll skip past it and return the next
|
9622
|
+
// token after adding an appropriate error message.
|
9596
9623
|
if (!width) {
|
9597
|
-
|
9624
|
+
pm_diagnostic_id_t diag_id;
|
9625
|
+
if (*parser->current.start >= 0x80) {
|
9626
|
+
diag_id = PM_ERR_INVALID_MULTIBYTE_CHARACTER;
|
9627
|
+
} else if (char_is_ascii_printable(*parser->current.start) || (*parser->current.start == '\\')) {
|
9628
|
+
diag_id = PM_ERR_INVALID_PRINTABLE_CHARACTER;
|
9629
|
+
} else {
|
9630
|
+
diag_id = PM_ERR_INVALID_CHARACTER;
|
9631
|
+
}
|
9632
|
+
|
9633
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, diag_id, *parser->current.start);
|
9598
9634
|
goto lex_next_token;
|
9599
9635
|
}
|
9600
9636
|
|
@@ -9701,7 +9737,7 @@ parser_lex(pm_parser_t *parser) {
|
|
9701
9737
|
// and then find the first one.
|
9702
9738
|
pm_lex_mode_t *lex_mode = parser->lex_modes.current;
|
9703
9739
|
const uint8_t *breakpoints = lex_mode->as.list.breakpoints;
|
9704
|
-
const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
9740
|
+
const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
9705
9741
|
|
9706
9742
|
// If we haven't found an escape yet, then this buffer will be
|
9707
9743
|
// unallocated since we can refer directly to the source string.
|
@@ -9710,7 +9746,7 @@ parser_lex(pm_parser_t *parser) {
|
|
9710
9746
|
while (breakpoint != NULL) {
|
9711
9747
|
// If we hit a null byte, skip directly past it.
|
9712
9748
|
if (*breakpoint == '\0') {
|
9713
|
-
breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1));
|
9749
|
+
breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1), true);
|
9714
9750
|
continue;
|
9715
9751
|
}
|
9716
9752
|
|
@@ -9729,7 +9765,7 @@ parser_lex(pm_parser_t *parser) {
|
|
9729
9765
|
// we need to continue on past it.
|
9730
9766
|
if (lex_mode->as.list.nesting > 0) {
|
9731
9767
|
parser->current.end = breakpoint + 1;
|
9732
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
9768
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
9733
9769
|
lex_mode->as.list.nesting--;
|
9734
9770
|
continue;
|
9735
9771
|
}
|
@@ -9814,7 +9850,7 @@ parser_lex(pm_parser_t *parser) {
|
|
9814
9850
|
}
|
9815
9851
|
|
9816
9852
|
token_buffer.cursor = parser->current.end;
|
9817
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
9853
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
9818
9854
|
continue;
|
9819
9855
|
}
|
9820
9856
|
|
@@ -9827,7 +9863,7 @@ parser_lex(pm_parser_t *parser) {
|
|
9827
9863
|
// that looked like an interpolated class or instance variable
|
9828
9864
|
// like "#@" but wasn't actually. In this case we'll just skip
|
9829
9865
|
// to the next breakpoint.
|
9830
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
9866
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
9831
9867
|
continue;
|
9832
9868
|
}
|
9833
9869
|
|
@@ -9842,7 +9878,7 @@ parser_lex(pm_parser_t *parser) {
|
|
9842
9878
|
// and find the next breakpoint.
|
9843
9879
|
assert(*breakpoint == lex_mode->as.list.incrementor);
|
9844
9880
|
parser->current.end = breakpoint + 1;
|
9845
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
9881
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
9846
9882
|
lex_mode->as.list.nesting++;
|
9847
9883
|
continue;
|
9848
9884
|
}
|
@@ -9881,14 +9917,14 @@ parser_lex(pm_parser_t *parser) {
|
|
9881
9917
|
// regular expression. We'll use strpbrk to find the first of these
|
9882
9918
|
// characters.
|
9883
9919
|
const uint8_t *breakpoints = lex_mode->as.regexp.breakpoints;
|
9884
|
-
const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
9920
|
+
const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
|
9885
9921
|
pm_token_buffer_t token_buffer = { { 0 }, 0 };
|
9886
9922
|
|
9887
9923
|
while (breakpoint != NULL) {
|
9888
9924
|
// If we hit a null byte, skip directly past it.
|
9889
9925
|
if (*breakpoint == '\0') {
|
9890
9926
|
parser->current.end = breakpoint + 1;
|
9891
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
9927
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
|
9892
9928
|
continue;
|
9893
9929
|
}
|
9894
9930
|
|
@@ -9910,7 +9946,7 @@ parser_lex(pm_parser_t *parser) {
|
|
9910
9946
|
// If the terminator is not a newline, then we can set
|
9911
9947
|
// the next breakpoint and continue.
|
9912
9948
|
parser->current.end = breakpoint + 1;
|
9913
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
9949
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
|
9914
9950
|
continue;
|
9915
9951
|
}
|
9916
9952
|
}
|
@@ -9920,7 +9956,7 @@ parser_lex(pm_parser_t *parser) {
|
|
9920
9956
|
if (*breakpoint == lex_mode->as.regexp.terminator) {
|
9921
9957
|
if (lex_mode->as.regexp.nesting > 0) {
|
9922
9958
|
parser->current.end = breakpoint + 1;
|
9923
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
9959
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
|
9924
9960
|
lex_mode->as.regexp.nesting--;
|
9925
9961
|
continue;
|
9926
9962
|
}
|
@@ -10019,7 +10055,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10019
10055
|
}
|
10020
10056
|
|
10021
10057
|
token_buffer.cursor = parser->current.end;
|
10022
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10058
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
|
10023
10059
|
continue;
|
10024
10060
|
}
|
10025
10061
|
|
@@ -10032,7 +10068,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10032
10068
|
// something that looked like an interpolated class or
|
10033
10069
|
// instance variable like "#@" but wasn't actually. In
|
10034
10070
|
// this case we'll just skip to the next breakpoint.
|
10035
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10071
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
|
10036
10072
|
continue;
|
10037
10073
|
}
|
10038
10074
|
|
@@ -10047,7 +10083,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10047
10083
|
// and find the next breakpoint.
|
10048
10084
|
assert(*breakpoint == lex_mode->as.regexp.incrementor);
|
10049
10085
|
parser->current.end = breakpoint + 1;
|
10050
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10086
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
|
10051
10087
|
lex_mode->as.regexp.nesting++;
|
10052
10088
|
continue;
|
10053
10089
|
}
|
@@ -10083,7 +10119,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10083
10119
|
// string. We'll use strpbrk to find the first of these characters.
|
10084
10120
|
pm_lex_mode_t *lex_mode = parser->lex_modes.current;
|
10085
10121
|
const uint8_t *breakpoints = lex_mode->as.string.breakpoints;
|
10086
|
-
const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10122
|
+
const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
10087
10123
|
|
10088
10124
|
// If we haven't found an escape yet, then this buffer will be
|
10089
10125
|
// unallocated since we can refer directly to the source string.
|
@@ -10095,7 +10131,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10095
10131
|
if (lex_mode->as.string.incrementor != '\0' && *breakpoint == lex_mode->as.string.incrementor) {
|
10096
10132
|
lex_mode->as.string.nesting++;
|
10097
10133
|
parser->current.end = breakpoint + 1;
|
10098
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10134
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
10099
10135
|
continue;
|
10100
10136
|
}
|
10101
10137
|
|
@@ -10107,7 +10143,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10107
10143
|
// to continue on past it.
|
10108
10144
|
if (lex_mode->as.string.nesting > 0) {
|
10109
10145
|
parser->current.end = breakpoint + 1;
|
10110
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10146
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
10111
10147
|
lex_mode->as.string.nesting--;
|
10112
10148
|
continue;
|
10113
10149
|
}
|
@@ -10149,7 +10185,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10149
10185
|
if (parser->heredoc_end == NULL) {
|
10150
10186
|
pm_newline_list_append(&parser->newline_list, breakpoint);
|
10151
10187
|
parser->current.end = breakpoint + 1;
|
10152
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10188
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
10153
10189
|
continue;
|
10154
10190
|
} else {
|
10155
10191
|
parser->current.end = breakpoint + 1;
|
@@ -10163,7 +10199,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10163
10199
|
case '\0':
|
10164
10200
|
// Skip directly past the null character.
|
10165
10201
|
parser->current.end = breakpoint + 1;
|
10166
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10202
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
10167
10203
|
break;
|
10168
10204
|
case '\\': {
|
10169
10205
|
// Here we hit escapes.
|
@@ -10232,7 +10268,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10232
10268
|
}
|
10233
10269
|
|
10234
10270
|
token_buffer.cursor = parser->current.end;
|
10235
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10271
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
10236
10272
|
break;
|
10237
10273
|
}
|
10238
10274
|
case '#': {
|
@@ -10243,7 +10279,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10243
10279
|
// looked like an interpolated class or instance variable like "#@"
|
10244
10280
|
// but wasn't actually. In this case we'll just skip to the next
|
10245
10281
|
// breakpoint.
|
10246
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10282
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
10247
10283
|
break;
|
10248
10284
|
}
|
10249
10285
|
|
@@ -10371,7 +10407,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10371
10407
|
breakpoints[2] = '\0';
|
10372
10408
|
}
|
10373
10409
|
|
10374
|
-
const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10410
|
+
const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
10375
10411
|
pm_token_buffer_t token_buffer = { { 0 }, 0 };
|
10376
10412
|
bool was_escaped_newline = false;
|
10377
10413
|
|
@@ -10380,7 +10416,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10380
10416
|
case '\0':
|
10381
10417
|
// Skip directly past the null character.
|
10382
10418
|
parser->current.end = breakpoint + 1;
|
10383
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10419
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
10384
10420
|
break;
|
10385
10421
|
case '\n': {
|
10386
10422
|
if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
|
@@ -10455,7 +10491,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10455
10491
|
// Otherwise we hit a newline and it wasn't followed by
|
10456
10492
|
// a terminator, so we can continue parsing.
|
10457
10493
|
parser->current.end = breakpoint + 1;
|
10458
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10494
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
10459
10495
|
break;
|
10460
10496
|
}
|
10461
10497
|
case '\\': {
|
@@ -10519,7 +10555,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10519
10555
|
}
|
10520
10556
|
|
10521
10557
|
token_buffer.cursor = parser->current.end;
|
10522
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10558
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
10523
10559
|
break;
|
10524
10560
|
}
|
10525
10561
|
case '#': {
|
@@ -10531,7 +10567,7 @@ parser_lex(pm_parser_t *parser) {
|
|
10531
10567
|
// or instance variable like "#@" but wasn't
|
10532
10568
|
// actually. In this case we'll just skip to the
|
10533
10569
|
// next breakpoint.
|
10534
|
-
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
10570
|
+
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
|
10535
10571
|
break;
|
10536
10572
|
}
|
10537
10573
|
|
@@ -11044,7 +11080,7 @@ parse_target(pm_parser_t *parser, pm_node_t *target) {
|
|
11044
11080
|
return target;
|
11045
11081
|
case PM_BACK_REFERENCE_READ_NODE:
|
11046
11082
|
case PM_NUMBERED_REFERENCE_READ_NODE:
|
11047
|
-
|
11083
|
+
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
|
11048
11084
|
return target;
|
11049
11085
|
case PM_GLOBAL_VARIABLE_READ_NODE:
|
11050
11086
|
assert(sizeof(pm_global_variable_target_node_t) == sizeof(pm_global_variable_read_node_t));
|
@@ -11182,7 +11218,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
|
|
11182
11218
|
}
|
11183
11219
|
case PM_BACK_REFERENCE_READ_NODE:
|
11184
11220
|
case PM_NUMBERED_REFERENCE_READ_NODE:
|
11185
|
-
|
11221
|
+
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
|
11186
11222
|
/* fallthrough */
|
11187
11223
|
case PM_GLOBAL_VARIABLE_READ_NODE: {
|
11188
11224
|
pm_global_variable_write_node_t *node = pm_global_variable_write_node_create(parser, target, operator, value);
|
@@ -11357,7 +11393,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
|
|
11357
11393
|
pm_multi_target_node_targets_append(parser, result, target);
|
11358
11394
|
} else if (!match1(parser, PM_TOKEN_EOF)) {
|
11359
11395
|
// If we get here, then we have a trailing , in a multi target node.
|
11360
|
-
// We'll
|
11396
|
+
// We'll add an implicit rest node to represent this.
|
11361
11397
|
pm_node_t *rest = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
|
11362
11398
|
pm_multi_target_node_targets_append(parser, result, rest);
|
11363
11399
|
break;
|
@@ -11447,8 +11483,13 @@ parse_statements(pm_parser_t *parser, pm_context_t context) {
|
|
11447
11483
|
|
11448
11484
|
while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
|
11449
11485
|
if (context_terminator(context, &parser->current)) break;
|
11450
|
-
} else {
|
11451
|
-
|
11486
|
+
} else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
|
11487
|
+
// This is an inlined version of accept1 because the error that we
|
11488
|
+
// want to add has varargs. If this happens again, we should
|
11489
|
+
// probably extract a helper function.
|
11490
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type));
|
11491
|
+
parser->previous.start = parser->previous.end;
|
11492
|
+
parser->previous.type = PM_TOKEN_MISSING;
|
11452
11493
|
}
|
11453
11494
|
}
|
11454
11495
|
|
@@ -12377,25 +12418,10 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, bool def_p) {
|
|
12377
12418
|
}
|
12378
12419
|
|
12379
12420
|
static inline pm_begin_node_t *
|
12380
|
-
parse_rescues_as_begin(pm_parser_t *parser, pm_statements_node_t *statements, bool def_p) {
|
12421
|
+
parse_rescues_as_begin(pm_parser_t *parser, const uint8_t *start, pm_statements_node_t *statements, bool def_p) {
|
12381
12422
|
pm_token_t no_begin_token = not_provided(parser);
|
12382
12423
|
pm_begin_node_t *begin_node = pm_begin_node_create(parser, &no_begin_token, statements);
|
12383
12424
|
parse_rescues(parser, begin_node, def_p);
|
12384
|
-
|
12385
|
-
// All nodes within a begin node are optional, so we look
|
12386
|
-
// for the earliest possible node that we can use to set
|
12387
|
-
// the BeginNode's start location
|
12388
|
-
const uint8_t *start = begin_node->base.location.start;
|
12389
|
-
if (begin_node->statements) {
|
12390
|
-
start = begin_node->statements->base.location.start;
|
12391
|
-
} else if (begin_node->rescue_clause) {
|
12392
|
-
start = begin_node->rescue_clause->base.location.start;
|
12393
|
-
} else if (begin_node->else_clause) {
|
12394
|
-
start = begin_node->else_clause->base.location.start;
|
12395
|
-
} else if (begin_node->ensure_clause) {
|
12396
|
-
start = begin_node->ensure_clause->base.location.start;
|
12397
|
-
}
|
12398
|
-
|
12399
12425
|
begin_node->base.location.start = start;
|
12400
12426
|
return begin_node;
|
12401
12427
|
}
|
@@ -12490,7 +12516,7 @@ parse_block(pm_parser_t *parser) {
|
|
12490
12516
|
|
12491
12517
|
if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
|
12492
12518
|
assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
|
12493
|
-
statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false);
|
12519
|
+
statements = (pm_node_t *) parse_rescues_as_begin(parser, opening.start, (pm_statements_node_t *) statements, false);
|
12494
12520
|
}
|
12495
12521
|
}
|
12496
12522
|
|
@@ -13857,7 +13883,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
|
|
13857
13883
|
pm_constant_id_t name_id = pm_parser_constant_id_constant(parser, "0it", 3);
|
13858
13884
|
variable = (pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0);
|
13859
13885
|
} else {
|
13860
|
-
|
13886
|
+
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
|
13861
13887
|
variable = (pm_node_t *) pm_local_variable_read_node_create(parser, &parser->previous, 0);
|
13862
13888
|
}
|
13863
13889
|
}
|
@@ -14166,7 +14192,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
|
|
14166
14192
|
parser_lex(parser);
|
14167
14193
|
|
14168
14194
|
if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
|
14169
|
-
expect1(parser, PM_TOKEN_STRING_END,
|
14195
|
+
expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
|
14170
14196
|
// If we get here, then we have an end immediately after a
|
14171
14197
|
// start. In that case we'll create an empty content token and
|
14172
14198
|
// return an uninterpolated string.
|
@@ -14223,15 +14249,19 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
|
|
14223
14249
|
parser_lex(parser);
|
14224
14250
|
} while (match1(parser, PM_TOKEN_STRING_CONTENT));
|
14225
14251
|
|
14226
|
-
expect1(parser, PM_TOKEN_STRING_END,
|
14252
|
+
expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
|
14227
14253
|
node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous);
|
14228
14254
|
} else if (accept1(parser, PM_TOKEN_LABEL_END) && !state_is_arg_labeled) {
|
14229
14255
|
node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &unescaped));
|
14230
14256
|
} else if (match1(parser, PM_TOKEN_EOF)) {
|
14231
|
-
pm_parser_err_token(parser, &opening,
|
14257
|
+
pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
|
14232
14258
|
node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped);
|
14259
|
+
} else if (accept1(parser, PM_TOKEN_STRING_END)) {
|
14260
|
+
node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
|
14233
14261
|
} else {
|
14234
|
-
|
14262
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_type_human(parser->previous.type));
|
14263
|
+
parser->previous.start = parser->previous.end;
|
14264
|
+
parser->previous.type = PM_TOKEN_MISSING;
|
14235
14265
|
node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
|
14236
14266
|
}
|
14237
14267
|
} else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
|
@@ -14246,7 +14276,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
|
|
14246
14276
|
if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
|
14247
14277
|
node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped);
|
14248
14278
|
pm_node_flag_set(node, parse_unescaped_encoding(parser));
|
14249
|
-
expect1(parser, PM_TOKEN_STRING_END,
|
14279
|
+
expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
|
14250
14280
|
} else if (accept1(parser, PM_TOKEN_LABEL_END)) {
|
14251
14281
|
node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &unescaped));
|
14252
14282
|
} else {
|
@@ -14337,6 +14367,29 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
|
|
14337
14367
|
return current;
|
14338
14368
|
}
|
14339
14369
|
|
14370
|
+
/**
|
14371
|
+
* Append an error to the error list on the parser using the given diagnostic
|
14372
|
+
* ID. This function is a specialization that handles formatting the specific
|
14373
|
+
* kind of error that is being appended.
|
14374
|
+
*/
|
14375
|
+
static void
|
14376
|
+
pm_parser_err_prefix(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
|
14377
|
+
switch (diag_id) {
|
14378
|
+
case PM_ERR_HASH_KEY: {
|
14379
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, diag_id, pm_token_type_human(parser->previous.type));
|
14380
|
+
break;
|
14381
|
+
}
|
14382
|
+
case PM_ERR_UNARY_RECEIVER: {
|
14383
|
+
const char *human = (parser->current.type == PM_TOKEN_EOF ? "end-of-input" : pm_token_type_human(parser->current.type));
|
14384
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, diag_id, human, parser->previous.start[0]);
|
14385
|
+
break;
|
14386
|
+
}
|
14387
|
+
default:
|
14388
|
+
pm_parser_err_previous(parser, diag_id);
|
14389
|
+
break;
|
14390
|
+
}
|
14391
|
+
}
|
14392
|
+
|
14340
14393
|
/**
|
14341
14394
|
* Parse an expression that begins with the previous node that we just lexed.
|
14342
14395
|
*/
|
@@ -14521,7 +14574,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
14521
14574
|
// If we didn't find a terminator and we didn't find a right
|
14522
14575
|
// parenthesis, then this is a syntax error.
|
14523
14576
|
if (!terminator_found) {
|
14524
|
-
|
14577
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type));
|
14525
14578
|
}
|
14526
14579
|
|
14527
14580
|
// Parse each statement within the parentheses.
|
@@ -14550,7 +14603,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
14550
14603
|
} else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
|
14551
14604
|
break;
|
14552
14605
|
} else {
|
14553
|
-
|
14606
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type));
|
14554
14607
|
}
|
14555
14608
|
}
|
14556
14609
|
|
@@ -15290,7 +15343,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
15290
15343
|
|
15291
15344
|
if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
|
15292
15345
|
assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
|
15293
|
-
statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false);
|
15346
|
+
statements = (pm_node_t *) parse_rescues_as_begin(parser, class_keyword.start, (pm_statements_node_t *) statements, false);
|
15294
15347
|
}
|
15295
15348
|
|
15296
15349
|
expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
|
@@ -15343,7 +15396,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
15343
15396
|
|
15344
15397
|
if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
|
15345
15398
|
assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
|
15346
|
-
statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false);
|
15399
|
+
statements = (pm_node_t *) parse_rescues_as_begin(parser, class_keyword.start, (pm_statements_node_t *) statements, false);
|
15347
15400
|
}
|
15348
15401
|
|
15349
15402
|
expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
|
@@ -15612,7 +15665,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
15612
15665
|
|
15613
15666
|
if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
|
15614
15667
|
assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
|
15615
|
-
statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, true);
|
15668
|
+
statements = (pm_node_t *) parse_rescues_as_begin(parser, def_keyword.start, (pm_statements_node_t *) statements, true);
|
15616
15669
|
}
|
15617
15670
|
|
15618
15671
|
pm_accepts_block_stack_pop(parser);
|
@@ -15631,10 +15684,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
15631
15684
|
* methods to override the unary operators, we should ignore
|
15632
15685
|
* the @ in the same way we do for symbols.
|
15633
15686
|
*/
|
15634
|
-
name.
|
15687
|
+
pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.start, parse_operator_symbol_name(&name));
|
15635
15688
|
|
15636
15689
|
return (pm_node_t *) pm_def_node_create(
|
15637
15690
|
parser,
|
15691
|
+
name_id,
|
15638
15692
|
&name,
|
15639
15693
|
receiver,
|
15640
15694
|
params,
|
@@ -15872,7 +15926,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
15872
15926
|
|
15873
15927
|
if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
|
15874
15928
|
assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
|
15875
|
-
statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false);
|
15929
|
+
statements = (pm_node_t *) parse_rescues_as_begin(parser, module_keyword.start, (pm_statements_node_t *) statements, false);
|
15876
15930
|
}
|
15877
15931
|
|
15878
15932
|
pm_constant_id_list_t locals = parser->current_scope->locals;
|
@@ -16463,7 +16517,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
16463
16517
|
// context of a multiple assignment. We enforce that here. We'll
|
16464
16518
|
// still lex past it though and create a missing node place.
|
16465
16519
|
if (binding_power != PM_BINDING_POWER_STATEMENT) {
|
16466
|
-
|
16520
|
+
pm_parser_err_prefix(parser, diag_id);
|
16467
16521
|
return (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
|
16468
16522
|
}
|
16469
16523
|
|
@@ -16486,7 +16540,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
16486
16540
|
parser_lex(parser);
|
16487
16541
|
|
16488
16542
|
pm_token_t operator = parser->previous;
|
16489
|
-
pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, binding_power < PM_BINDING_POWER_MATCH,
|
16543
|
+
pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, binding_power < PM_BINDING_POWER_MATCH, PM_ERR_UNARY_RECEIVER);
|
16490
16544
|
pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "!");
|
16491
16545
|
|
16492
16546
|
pm_conditional_predicate(receiver);
|
@@ -16496,7 +16550,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
16496
16550
|
parser_lex(parser);
|
16497
16551
|
|
16498
16552
|
pm_token_t operator = parser->previous;
|
16499
|
-
pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false,
|
16553
|
+
pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER);
|
16500
16554
|
pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "~");
|
16501
16555
|
|
16502
16556
|
return (pm_node_t *) node;
|
@@ -16505,7 +16559,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
16505
16559
|
parser_lex(parser);
|
16506
16560
|
|
16507
16561
|
pm_token_t operator = parser->previous;
|
16508
|
-
pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false,
|
16562
|
+
pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER);
|
16509
16563
|
pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "-@");
|
16510
16564
|
|
16511
16565
|
return (pm_node_t *) node;
|
@@ -16514,7 +16568,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
16514
16568
|
parser_lex(parser);
|
16515
16569
|
|
16516
16570
|
pm_token_t operator = parser->previous;
|
16517
|
-
pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false,
|
16571
|
+
pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER);
|
16518
16572
|
|
16519
16573
|
if (accept1(parser, PM_TOKEN_STAR_STAR)) {
|
16520
16574
|
pm_token_t exponent_operator = parser->previous;
|
@@ -16605,7 +16659,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
16605
16659
|
|
16606
16660
|
if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
|
16607
16661
|
assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
|
16608
|
-
body = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) body, false);
|
16662
|
+
body = (pm_node_t *) parse_rescues_as_begin(parser, opening.start, (pm_statements_node_t *) body, false);
|
16609
16663
|
}
|
16610
16664
|
|
16611
16665
|
expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
|
@@ -16630,7 +16684,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
16630
16684
|
parser_lex(parser);
|
16631
16685
|
|
16632
16686
|
pm_token_t operator = parser->previous;
|
16633
|
-
pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false,
|
16687
|
+
pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER);
|
16634
16688
|
pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "+@");
|
16635
16689
|
|
16636
16690
|
return (pm_node_t *) node;
|
@@ -16653,7 +16707,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
16653
16707
|
// here because it will provide more context in addition to the
|
16654
16708
|
// recoverable error that we will also add.
|
16655
16709
|
if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
|
16656
|
-
|
16710
|
+
pm_parser_err_prefix(parser, diag_id);
|
16657
16711
|
}
|
16658
16712
|
|
16659
16713
|
// If we get here, then we are assuming this token is closing a
|
@@ -16666,7 +16720,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
16666
16720
|
// have an unexpected token.
|
16667
16721
|
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_type_human(parser->current.type));
|
16668
16722
|
} else {
|
16669
|
-
|
16723
|
+
pm_parser_err_prefix(parser, diag_id);
|
16670
16724
|
}
|
16671
16725
|
|
16672
16726
|
return (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
|
@@ -16900,7 +16954,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
|
|
16900
16954
|
switch (PM_NODE_TYPE(node)) {
|
16901
16955
|
case PM_BACK_REFERENCE_READ_NODE:
|
16902
16956
|
case PM_NUMBERED_REFERENCE_READ_NODE:
|
16903
|
-
|
16957
|
+
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
|
16904
16958
|
/* fallthrough */
|
16905
16959
|
case PM_GLOBAL_VARIABLE_READ_NODE: {
|
16906
16960
|
parser_lex(parser);
|
@@ -17011,7 +17065,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
|
|
17011
17065
|
switch (PM_NODE_TYPE(node)) {
|
17012
17066
|
case PM_BACK_REFERENCE_READ_NODE:
|
17013
17067
|
case PM_NUMBERED_REFERENCE_READ_NODE:
|
17014
|
-
|
17068
|
+
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
|
17015
17069
|
/* fallthrough */
|
17016
17070
|
case PM_GLOBAL_VARIABLE_READ_NODE: {
|
17017
17071
|
parser_lex(parser);
|
@@ -17132,7 +17186,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
|
|
17132
17186
|
switch (PM_NODE_TYPE(node)) {
|
17133
17187
|
case PM_BACK_REFERENCE_READ_NODE:
|
17134
17188
|
case PM_NUMBERED_REFERENCE_READ_NODE:
|
17135
|
-
|
17189
|
+
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
|
17136
17190
|
/* fallthrough */
|
17137
17191
|
case PM_GLOBAL_VARIABLE_READ_NODE: {
|
17138
17192
|
parser_lex(parser);
|
@@ -17796,6 +17850,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
|
|
17796
17850
|
.current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
|
17797
17851
|
.next_start = NULL,
|
17798
17852
|
.heredoc_end = NULL,
|
17853
|
+
.data_loc = { .start = NULL, .end = NULL },
|
17799
17854
|
.comment_list = { 0 },
|
17800
17855
|
.magic_comment_list = { 0 },
|
17801
17856
|
.warning_list = { 0 },
|