prism 0.21.0 → 0.23.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 +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 },
|