prism 0.28.0 → 0.29.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 +20 -1
- data/config.yml +29 -17
- data/ext/prism/api_node.c +40 -40
- data/ext/prism/extconf.rb +27 -23
- data/ext/prism/extension.h +1 -1
- data/include/prism/ast.h +32 -32
- data/include/prism/diagnostic.h +11 -1
- data/include/prism/version.h +2 -2
- data/lib/prism/desugar_compiler.rb +4 -4
- data/lib/prism/dot_visitor.rb +32 -32
- data/lib/prism/dsl.rb +16 -16
- data/lib/prism/ffi.rb +1 -1
- data/lib/prism/inspect_visitor.rb +16 -16
- data/lib/prism/node.rb +148 -148
- data/lib/prism/node_ext.rb +156 -14
- data/lib/prism/parse_result/comments.rb +1 -1
- data/lib/prism/parse_result/newlines.rb +1 -1
- data/lib/prism/reflection.rb +8 -8
- data/lib/prism/serialize.rb +12 -2
- data/lib/prism/translation/parser/compiler.rb +154 -24
- data/lib/prism/translation/parser.rb +1 -1
- data/lib/prism/translation/ripper.rb +16 -16
- data/lib/prism/translation/ruby_parser.rb +9 -9
- data/prism.gemspec +2 -1
- data/rbi/prism/node.rbi +51 -51
- data/rbi/prism/node_ext.rbi +5 -0
- data/rbi/prism/parse_result.rbi +1 -1
- data/sig/prism/dsl.rbs +9 -9
- data/sig/prism/lex_compat.rbs +10 -0
- data/sig/prism/node.rbs +44 -44
- data/sig/prism/node_ext.rbs +4 -0
- data/src/diagnostic.c +30 -11
- data/src/node.c +48 -48
- data/src/prettyprint.c +48 -48
- data/src/prism.c +256 -133
- data/src/serialize.c +16 -16
- data/src/token_type.c +2 -2
- metadata +3 -2
data/src/prism.c
CHANGED
@@ -749,42 +749,97 @@ pm_parser_scope_find(pm_parser_t *parser, uint32_t depth) {
|
|
749
749
|
return scope;
|
750
750
|
}
|
751
751
|
|
752
|
-
|
753
|
-
|
752
|
+
typedef enum {
|
753
|
+
PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
|
754
|
+
PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
|
755
|
+
PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
|
756
|
+
} pm_scope_forwarding_param_check_result_t;
|
757
|
+
|
758
|
+
static pm_scope_forwarding_param_check_result_t
|
759
|
+
pm_parser_scope_forwarding_param_check(pm_parser_t *parser, const uint8_t mask) {
|
754
760
|
pm_scope_t *scope = parser->current_scope;
|
755
|
-
|
761
|
+
bool conflict = false;
|
762
|
+
|
763
|
+
while (scope != NULL) {
|
756
764
|
if (scope->parameters & mask) {
|
757
|
-
if (
|
758
|
-
|
759
|
-
|
765
|
+
if (scope->closed) {
|
766
|
+
if (conflict) {
|
767
|
+
return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
|
768
|
+
} else {
|
769
|
+
return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
|
770
|
+
}
|
760
771
|
}
|
761
|
-
|
772
|
+
|
773
|
+
conflict = true;
|
762
774
|
}
|
775
|
+
|
763
776
|
if (scope->closed) break;
|
764
777
|
scope = scope->previous;
|
765
778
|
}
|
766
779
|
|
767
|
-
|
780
|
+
return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
|
768
781
|
}
|
769
782
|
|
770
|
-
static
|
783
|
+
static void
|
771
784
|
pm_parser_scope_forwarding_block_check(pm_parser_t *parser, const pm_token_t * token) {
|
772
|
-
pm_parser_scope_forwarding_param_check(parser,
|
785
|
+
switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
|
786
|
+
case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
|
787
|
+
// Pass.
|
788
|
+
break;
|
789
|
+
case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
|
790
|
+
pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
|
791
|
+
break;
|
792
|
+
case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
|
793
|
+
pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
|
794
|
+
break;
|
795
|
+
}
|
773
796
|
}
|
774
797
|
|
775
|
-
static
|
798
|
+
static void
|
776
799
|
pm_parser_scope_forwarding_positionals_check(pm_parser_t *parser, const pm_token_t * token) {
|
777
|
-
pm_parser_scope_forwarding_param_check(parser,
|
800
|
+
switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
|
801
|
+
case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
|
802
|
+
// Pass.
|
803
|
+
break;
|
804
|
+
case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
|
805
|
+
pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
|
806
|
+
break;
|
807
|
+
case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
|
808
|
+
pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
|
809
|
+
break;
|
810
|
+
}
|
778
811
|
}
|
779
812
|
|
780
|
-
static
|
781
|
-
pm_parser_scope_forwarding_all_check(pm_parser_t *parser, const pm_token_t *
|
782
|
-
pm_parser_scope_forwarding_param_check(parser,
|
813
|
+
static void
|
814
|
+
pm_parser_scope_forwarding_all_check(pm_parser_t *parser, const pm_token_t *token) {
|
815
|
+
switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
|
816
|
+
case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
|
817
|
+
// Pass.
|
818
|
+
break;
|
819
|
+
case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
|
820
|
+
// This shouldn't happen, because ... is not allowed in the
|
821
|
+
// declaration of blocks. If we get here, we assume we already have
|
822
|
+
// an error for this.
|
823
|
+
break;
|
824
|
+
case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
|
825
|
+
pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
|
826
|
+
break;
|
827
|
+
}
|
783
828
|
}
|
784
829
|
|
785
|
-
static
|
830
|
+
static void
|
786
831
|
pm_parser_scope_forwarding_keywords_check(pm_parser_t *parser, const pm_token_t * token) {
|
787
|
-
pm_parser_scope_forwarding_param_check(parser,
|
832
|
+
switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
|
833
|
+
case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
|
834
|
+
// Pass.
|
835
|
+
break;
|
836
|
+
case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
|
837
|
+
pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
|
838
|
+
break;
|
839
|
+
case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
|
840
|
+
pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
|
841
|
+
break;
|
842
|
+
}
|
788
843
|
}
|
789
844
|
|
790
845
|
/**
|
@@ -1703,7 +1758,7 @@ char_is_identifier_utf8(const uint8_t *b, const uint8_t *end) {
|
|
1703
1758
|
* it's important that it be as fast as possible.
|
1704
1759
|
*/
|
1705
1760
|
static inline size_t
|
1706
|
-
char_is_identifier(pm_parser_t *parser, const uint8_t *b) {
|
1761
|
+
char_is_identifier(const pm_parser_t *parser, const uint8_t *b) {
|
1707
1762
|
if (parser->encoding_changed) {
|
1708
1763
|
size_t width;
|
1709
1764
|
if ((width = parser->encoding->alnum_char(b, parser->end - b)) != 0) {
|
@@ -3025,8 +3080,8 @@ pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target,
|
|
3025
3080
|
.message_loc = target->message_loc,
|
3026
3081
|
.read_name = 0,
|
3027
3082
|
.write_name = target->name,
|
3028
|
-
.
|
3029
|
-
.
|
3083
|
+
.binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
|
3084
|
+
.binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
|
3030
3085
|
.value = value
|
3031
3086
|
};
|
3032
3087
|
|
@@ -3064,8 +3119,8 @@ pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target,
|
|
3064
3119
|
.arguments = target->arguments,
|
3065
3120
|
.closing_loc = target->closing_loc,
|
3066
3121
|
.block = target->block,
|
3067
|
-
.
|
3068
|
-
.
|
3122
|
+
.binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
|
3123
|
+
.binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
|
3069
3124
|
.value = value
|
3070
3125
|
};
|
3071
3126
|
|
@@ -3409,9 +3464,9 @@ pm_class_variable_operator_write_node_create(pm_parser_t *parser, pm_class_varia
|
|
3409
3464
|
},
|
3410
3465
|
.name = target->name,
|
3411
3466
|
.name_loc = target->base.location,
|
3412
|
-
.
|
3467
|
+
.binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
|
3413
3468
|
.value = value,
|
3414
|
-
.
|
3469
|
+
.binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
3415
3470
|
};
|
3416
3471
|
|
3417
3472
|
return node;
|
@@ -3525,9 +3580,9 @@ pm_constant_path_operator_write_node_create(pm_parser_t *parser, pm_constant_pat
|
|
3525
3580
|
}
|
3526
3581
|
},
|
3527
3582
|
.target = target,
|
3528
|
-
.
|
3583
|
+
.binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
|
3529
3584
|
.value = value,
|
3530
|
-
.
|
3585
|
+
.binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
3531
3586
|
};
|
3532
3587
|
|
3533
3588
|
return node;
|
@@ -3652,9 +3707,9 @@ pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_nod
|
|
3652
3707
|
},
|
3653
3708
|
.name = target->name,
|
3654
3709
|
.name_loc = target->base.location,
|
3655
|
-
.
|
3710
|
+
.binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
|
3656
3711
|
.value = value,
|
3657
|
-
.
|
3712
|
+
.binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
3658
3713
|
};
|
3659
3714
|
|
3660
3715
|
return node;
|
@@ -4505,9 +4560,9 @@ pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *ta
|
|
4505
4560
|
},
|
4506
4561
|
.name = pm_global_variable_write_name(parser, target),
|
4507
4562
|
.name_loc = target->location,
|
4508
|
-
.
|
4563
|
+
.binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
|
4509
4564
|
.value = value,
|
4510
|
-
.
|
4565
|
+
.binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
4511
4566
|
};
|
4512
4567
|
|
4513
4568
|
return node;
|
@@ -5013,9 +5068,9 @@ pm_instance_variable_operator_write_node_create(pm_parser_t *parser, pm_instance
|
|
5013
5068
|
},
|
5014
5069
|
.name = target->name,
|
5015
5070
|
.name_loc = target->base.location,
|
5016
|
-
.
|
5071
|
+
.binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
|
5017
5072
|
.value = value,
|
5018
|
-
.
|
5073
|
+
.binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
5019
5074
|
};
|
5020
5075
|
|
5021
5076
|
return node;
|
@@ -5609,10 +5664,10 @@ pm_local_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *tar
|
|
5609
5664
|
}
|
5610
5665
|
},
|
5611
5666
|
.name_loc = target->location,
|
5612
|
-
.
|
5667
|
+
.binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
|
5613
5668
|
.value = value,
|
5614
5669
|
.name = name,
|
5615
|
-
.
|
5670
|
+
.binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
|
5616
5671
|
.depth = depth
|
5617
5672
|
};
|
5618
5673
|
|
@@ -6891,7 +6946,7 @@ pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node,
|
|
6891
6946
|
case PM_REDO_NODE:
|
6892
6947
|
case PM_RETRY_NODE:
|
6893
6948
|
case PM_RETURN_NODE:
|
6894
|
-
pm_parser_warn_node(parser,
|
6949
|
+
pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
|
6895
6950
|
break;
|
6896
6951
|
default:
|
6897
6952
|
break;
|
@@ -8339,7 +8394,12 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
|
|
8339
8394
|
// If we have hit a ractor pragma, attempt to lex that.
|
8340
8395
|
uint32_t value_length = (uint32_t) (value_end - value_start);
|
8341
8396
|
if (key_length == 24 && pm_strncasecmp(key_source, (const uint8_t *) "shareable_constant_value", 24) == 0) {
|
8342
|
-
|
8397
|
+
const uint8_t *cursor = parser->current.start;
|
8398
|
+
while ((cursor > parser->start) && ((cursor[-1] == ' ') || (cursor[-1] == '\t'))) cursor--;
|
8399
|
+
|
8400
|
+
if (!((cursor == parser->start) || (cursor[-1] == '\n'))) {
|
8401
|
+
pm_parser_warn_token(parser, &parser->current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
|
8402
|
+
} else if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "none", 4) == 0) {
|
8343
8403
|
pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
|
8344
8404
|
} else if (value_length == 7 && pm_strncasecmp(value_start, (const uint8_t *) "literal", 7) == 0) {
|
8345
8405
|
pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
|
@@ -8796,6 +8856,16 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
|
|
8796
8856
|
type = lex_optional_float_suffix(parser, seen_e);
|
8797
8857
|
}
|
8798
8858
|
|
8859
|
+
// At this point we have a completed number, but we want to provide the user
|
8860
|
+
// with a good experience if they put an additional .xxx fractional
|
8861
|
+
// component on the end, so we'll check for that here.
|
8862
|
+
if (peek_offset(parser, 0) == '.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
|
8863
|
+
const uint8_t *fraction_start = parser->current.end;
|
8864
|
+
const uint8_t *fraction_end = parser->current.end + 2;
|
8865
|
+
fraction_end += pm_strspn_decimal_digit(fraction_end, parser->end - fraction_end);
|
8866
|
+
pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
|
8867
|
+
}
|
8868
|
+
|
8799
8869
|
return type;
|
8800
8870
|
}
|
8801
8871
|
|
@@ -9297,12 +9367,20 @@ escape_hexadecimal_digit(const uint8_t value) {
|
|
9297
9367
|
* validated.
|
9298
9368
|
*/
|
9299
9369
|
static inline uint32_t
|
9300
|
-
escape_unicode(const uint8_t *string, size_t length) {
|
9370
|
+
escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length) {
|
9301
9371
|
uint32_t value = 0;
|
9302
9372
|
for (size_t index = 0; index < length; index++) {
|
9303
9373
|
if (index != 0) value <<= 4;
|
9304
9374
|
value |= escape_hexadecimal_digit(string[index]);
|
9305
9375
|
}
|
9376
|
+
|
9377
|
+
// Here we're going to verify that the value is actually a valid Unicode
|
9378
|
+
// codepoint and not a surrogate pair.
|
9379
|
+
if (value >= 0xD800 && value <= 0xDFFF) {
|
9380
|
+
pm_parser_err(parser, string, string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
|
9381
|
+
return 0xFFFD;
|
9382
|
+
}
|
9383
|
+
|
9306
9384
|
return value;
|
9307
9385
|
}
|
9308
9386
|
|
@@ -9551,7 +9629,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
|
|
9551
9629
|
pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end - start));
|
9552
9630
|
}
|
9553
9631
|
|
9554
|
-
escape_write_byte_encoded(parser, buffer, value);
|
9632
|
+
escape_write_byte_encoded(parser, buffer, escape_byte(value, flags));
|
9555
9633
|
} else {
|
9556
9634
|
pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
|
9557
9635
|
}
|
@@ -9590,7 +9668,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
|
|
9590
9668
|
extra_codepoints_start = unicode_start;
|
9591
9669
|
}
|
9592
9670
|
|
9593
|
-
uint32_t value = escape_unicode(unicode_start, hexadecimal_length);
|
9671
|
+
uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
|
9594
9672
|
escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value);
|
9595
9673
|
|
9596
9674
|
parser->current.end += pm_strspn_whitespace(parser->current.end, parser->end - parser->current.end);
|
@@ -9615,7 +9693,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
|
|
9615
9693
|
size_t length = pm_strspn_hexadecimal_digit(parser->current.end, MIN(parser->end - parser->current.end, 4));
|
9616
9694
|
|
9617
9695
|
if (length == 4) {
|
9618
|
-
uint32_t value = escape_unicode(parser->current.end, 4);
|
9696
|
+
uint32_t value = escape_unicode(parser, parser->current.end, 4);
|
9619
9697
|
|
9620
9698
|
if (flags & PM_ESCAPE_FLAG_REGEXP) {
|
9621
9699
|
pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end + 4 - start));
|
@@ -9629,6 +9707,10 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
|
|
9629
9707
|
}
|
9630
9708
|
}
|
9631
9709
|
|
9710
|
+
if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
|
9711
|
+
pm_parser_err(parser, start, parser->current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
|
9712
|
+
}
|
9713
|
+
|
9632
9714
|
return;
|
9633
9715
|
}
|
9634
9716
|
case 'c': {
|
@@ -14036,31 +14118,37 @@ static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
|
|
14036
14118
|
* Check if current parameter follows valid parameters ordering. If not it adds
|
14037
14119
|
* an error to the list without stopping the parsing, otherwise sets the
|
14038
14120
|
* parameters state to the one corresponding to the current parameter.
|
14121
|
+
*
|
14122
|
+
* It returns true if it was successful, and false otherwise.
|
14039
14123
|
*/
|
14040
|
-
static
|
14124
|
+
static bool
|
14041
14125
|
update_parameter_state(pm_parser_t *parser, pm_token_t *token, pm_parameters_order_t *current) {
|
14042
14126
|
pm_parameters_order_t state = parameters_ordering[token->type];
|
14043
|
-
if (state == PM_PARAMETERS_NO_CHANGE) return;
|
14127
|
+
if (state == PM_PARAMETERS_NO_CHANGE) return true;
|
14044
14128
|
|
14045
14129
|
// If we see another ordered argument after a optional argument
|
14046
14130
|
// we only continue parsing ordered arguments until we stop seeing ordered arguments.
|
14047
14131
|
if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
|
14048
14132
|
*current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
|
14049
|
-
return;
|
14133
|
+
return true;
|
14050
14134
|
} else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
|
14051
|
-
return;
|
14135
|
+
return true;
|
14052
14136
|
}
|
14053
14137
|
|
14054
14138
|
if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
|
14055
14139
|
pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
|
14056
|
-
|
14057
|
-
|
14058
|
-
|
14140
|
+
return false;
|
14141
|
+
} else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
|
14142
|
+
pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
|
14143
|
+
return false;
|
14144
|
+
} else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
|
14059
14145
|
// We know what transition we failed on, so we can provide a better error here.
|
14060
14146
|
pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
|
14061
|
-
|
14062
|
-
*current = state;
|
14147
|
+
return false;
|
14063
14148
|
}
|
14149
|
+
|
14150
|
+
if (state < *current) *current = state;
|
14151
|
+
return true;
|
14064
14152
|
}
|
14065
14153
|
|
14066
14154
|
/**
|
@@ -14129,27 +14217,22 @@ parse_parameters(
|
|
14129
14217
|
pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
|
14130
14218
|
}
|
14131
14219
|
|
14132
|
-
|
14133
|
-
|
14134
|
-
parser_lex(parser);
|
14220
|
+
bool succeeded = update_parameter_state(parser, &parser->current, &order);
|
14221
|
+
parser_lex(parser);
|
14135
14222
|
|
14136
|
-
|
14223
|
+
parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL;
|
14224
|
+
pm_forwarding_parameter_node_t *param = pm_forwarding_parameter_node_create(parser, &parser->previous);
|
14137
14225
|
|
14138
|
-
|
14139
|
-
|
14140
|
-
|
14141
|
-
|
14142
|
-
|
14143
|
-
|
14144
|
-
|
14145
|
-
params->keyword_rest = NULL;
|
14146
|
-
}
|
14147
|
-
pm_parameters_node_keyword_rest_set(params, (pm_node_t *)param);
|
14148
|
-
} else {
|
14149
|
-
update_parameter_state(parser, &parser->current, &order);
|
14150
|
-
parser_lex(parser);
|
14226
|
+
if (params->keyword_rest != NULL) {
|
14227
|
+
// If we already have a keyword rest parameter, then we replace it with the
|
14228
|
+
// forwarding parameter and move the keyword rest parameter to the posts list.
|
14229
|
+
pm_node_t *keyword_rest = params->keyword_rest;
|
14230
|
+
pm_parameters_node_posts_append(params, keyword_rest);
|
14231
|
+
if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
|
14232
|
+
params->keyword_rest = NULL;
|
14151
14233
|
}
|
14152
14234
|
|
14235
|
+
pm_parameters_node_keyword_rest_set(params, (pm_node_t *) param);
|
14153
14236
|
break;
|
14154
14237
|
}
|
14155
14238
|
case PM_TOKEN_CLASS_VARIABLE:
|
@@ -14244,6 +14327,12 @@ parse_parameters(
|
|
14244
14327
|
pm_token_t local = name;
|
14245
14328
|
local.end -= 1;
|
14246
14329
|
|
14330
|
+
if (parser->encoding_changed ? parser->encoding->isupper_char(local.start, local.end - local.start) : pm_encoding_utf_8_isupper_char(local.start, local.end - local.start)) {
|
14331
|
+
pm_parser_err(parser, local.start, local.end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
|
14332
|
+
} else if (local.end[-1] == '!' || local.end[-1] == '?') {
|
14333
|
+
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
|
14334
|
+
}
|
14335
|
+
|
14247
14336
|
bool repeated = pm_parser_parameter_name_check(parser, &local);
|
14248
14337
|
pm_parser_local_add_token(parser, &local, 1);
|
14249
14338
|
|
@@ -14808,7 +14897,7 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept
|
|
14808
14897
|
arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
|
14809
14898
|
} else {
|
14810
14899
|
pm_accepts_block_stack_push(parser, true);
|
14811
|
-
parse_arguments(parser, arguments,
|
14900
|
+
parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT);
|
14812
14901
|
|
14813
14902
|
if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
|
14814
14903
|
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_type_human(parser->current.type));
|
@@ -14826,7 +14915,7 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept
|
|
14826
14915
|
// If we get here, then the subsequent token cannot be used as an infix
|
14827
14916
|
// operator. In this case we assume the subsequent token is part of an
|
14828
14917
|
// argument to this method call.
|
14829
|
-
parse_arguments(parser, arguments,
|
14918
|
+
parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF);
|
14830
14919
|
|
14831
14920
|
// If we have done with the arguments and still not consumed the comma,
|
14832
14921
|
// then we have a trailing comma where we need to check whether it is
|
@@ -14857,11 +14946,8 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept
|
|
14857
14946
|
if (arguments->block == NULL && !arguments->has_forwarding) {
|
14858
14947
|
arguments->block = (pm_node_t *) block;
|
14859
14948
|
} else {
|
14860
|
-
|
14861
|
-
|
14862
|
-
} else {
|
14863
|
-
pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
|
14864
|
-
}
|
14949
|
+
pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
|
14950
|
+
|
14865
14951
|
if (arguments->block != NULL) {
|
14866
14952
|
if (arguments->arguments == NULL) {
|
14867
14953
|
arguments->arguments = pm_arguments_node_create(parser);
|
@@ -15846,8 +15932,12 @@ parse_heredoc_dedent(pm_parser_t *parser, pm_node_list_t *nodes, size_t common_w
|
|
15846
15932
|
nodes->size = write_index;
|
15847
15933
|
}
|
15848
15934
|
|
15935
|
+
#define PM_PARSE_PATTERN_SINGLE 0
|
15936
|
+
#define PM_PARSE_PATTERN_TOP 1
|
15937
|
+
#define PM_PARSE_PATTERN_MULTI 2
|
15938
|
+
|
15849
15939
|
static pm_node_t *
|
15850
|
-
parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures,
|
15940
|
+
parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flags, pm_diagnostic_id_t diag_id);
|
15851
15941
|
|
15852
15942
|
/**
|
15853
15943
|
* Add the newly created local to the list of captures for this pattern matching
|
@@ -15895,7 +15985,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
|
|
15895
15985
|
accept1(parser, PM_TOKEN_NEWLINE);
|
15896
15986
|
|
15897
15987
|
if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
|
15898
|
-
inner = parse_pattern(parser, captures,
|
15988
|
+
inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET);
|
15899
15989
|
accept1(parser, PM_TOKEN_NEWLINE);
|
15900
15990
|
expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
|
15901
15991
|
}
|
@@ -15907,7 +15997,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
|
|
15907
15997
|
accept1(parser, PM_TOKEN_NEWLINE);
|
15908
15998
|
|
15909
15999
|
if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
|
15910
|
-
inner = parse_pattern(parser, captures,
|
16000
|
+
inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN);
|
15911
16001
|
accept1(parser, PM_TOKEN_NEWLINE);
|
15912
16002
|
expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
|
15913
16003
|
}
|
@@ -16055,6 +16145,33 @@ parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures)
|
|
16055
16145
|
return (pm_node_t *) pm_assoc_splat_node_create(parser, value, &operator);
|
16056
16146
|
}
|
16057
16147
|
|
16148
|
+
/**
|
16149
|
+
* Check that the slice of the source given by the bounds parameters constitutes
|
16150
|
+
* a valid local variable name.
|
16151
|
+
*/
|
16152
|
+
static bool
|
16153
|
+
pm_slice_is_valid_local(const pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
|
16154
|
+
ptrdiff_t length = end - start;
|
16155
|
+
if (length == 0) return false;
|
16156
|
+
|
16157
|
+
// First ensure that it starts with a valid identifier starting character.
|
16158
|
+
size_t width = char_is_identifier_start(parser, start);
|
16159
|
+
if (width == 0) return false;
|
16160
|
+
|
16161
|
+
// Next, ensure that it's not an uppercase character.
|
16162
|
+
if (parser->encoding_changed) {
|
16163
|
+
if (parser->encoding->isupper_char(start, length)) return false;
|
16164
|
+
} else {
|
16165
|
+
if (pm_encoding_utf_8_isupper_char(start, length)) return false;
|
16166
|
+
}
|
16167
|
+
|
16168
|
+
// Next, iterate through all of the bytes of the string to ensure that they
|
16169
|
+
// are all valid identifier characters.
|
16170
|
+
const uint8_t *cursor = start + width;
|
16171
|
+
while ((cursor < end) && (width = char_is_identifier(parser, cursor))) cursor += width;
|
16172
|
+
return cursor == end;
|
16173
|
+
}
|
16174
|
+
|
16058
16175
|
/**
|
16059
16176
|
* Create an implicit node for the value of a hash pattern that has omitted the
|
16060
16177
|
* value. This will use an implicit local variable target.
|
@@ -16062,14 +16179,18 @@ parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures)
|
|
16062
16179
|
static pm_node_t *
|
16063
16180
|
parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_symbol_node_t *key) {
|
16064
16181
|
const pm_location_t *value_loc = &((pm_symbol_node_t *) key)->value_loc;
|
16065
|
-
pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, value_loc->start, value_loc->end);
|
16066
16182
|
|
16183
|
+
pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, value_loc->start, value_loc->end);
|
16067
16184
|
int depth = -1;
|
16068
|
-
|
16069
|
-
|
16070
|
-
PM_PARSER_ERR_LOCATION_FORMAT(parser, value_loc, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (int) (value_loc->end - value_loc->start), (const char *) value_loc->start);
|
16071
|
-
} else {
|
16185
|
+
|
16186
|
+
if (pm_slice_is_valid_local(parser, value_loc->start, value_loc->end)) {
|
16072
16187
|
depth = pm_parser_local_depth_constant_id(parser, constant_id);
|
16188
|
+
} else {
|
16189
|
+
pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
|
16190
|
+
|
16191
|
+
if ((value_loc->end > value_loc->start) && ((value_loc->end[-1] == '!') || (value_loc->end[-1] == '?'))) {
|
16192
|
+
PM_PARSER_ERR_LOCATION_FORMAT(parser, value_loc, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (int) (value_loc->end - value_loc->start), (const char *) value_loc->start);
|
16193
|
+
}
|
16073
16194
|
}
|
16074
16195
|
|
16075
16196
|
if (depth == -1) {
|
@@ -16124,7 +16245,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
|
|
16124
16245
|
} else {
|
16125
16246
|
// Here we have a value for the first assoc in the list, so
|
16126
16247
|
// we will parse it now.
|
16127
|
-
value = parse_pattern(parser, captures,
|
16248
|
+
value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY);
|
16128
16249
|
}
|
16129
16250
|
|
16130
16251
|
pm_token_t operator = not_provided(parser);
|
@@ -16139,7 +16260,8 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
|
|
16139
16260
|
// If we get anything else, then this is an error. For this we'll
|
16140
16261
|
// create a missing node for the value and create an assoc node for
|
16141
16262
|
// the first node in the list.
|
16142
|
-
|
16263
|
+
pm_diagnostic_id_t diag_id = PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE) ? PM_ERR_PATTERN_HASH_KEY_INTERPOLATED : PM_ERR_PATTERN_HASH_KEY_LABEL;
|
16264
|
+
pm_parser_err_node(parser, first_node, diag_id);
|
16143
16265
|
|
16144
16266
|
pm_token_t operator = not_provided(parser);
|
16145
16267
|
pm_node_t *value = (pm_node_t *) pm_missing_node_create(parser, first_node->location.start, first_node->location.end);
|
@@ -16176,7 +16298,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
|
|
16176
16298
|
if (match7(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)) {
|
16177
16299
|
value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key);
|
16178
16300
|
} else {
|
16179
|
-
value = parse_pattern(parser, captures,
|
16301
|
+
value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY);
|
16180
16302
|
}
|
16181
16303
|
|
16182
16304
|
pm_token_t operator = not_provided(parser);
|
@@ -16233,7 +16355,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
|
|
16233
16355
|
|
16234
16356
|
// Otherwise, we'll parse the inner pattern, then deal with it depending
|
16235
16357
|
// on the type it returns.
|
16236
|
-
pm_node_t *inner = parse_pattern(parser, captures,
|
16358
|
+
pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET);
|
16237
16359
|
|
16238
16360
|
accept1(parser, PM_TOKEN_NEWLINE);
|
16239
16361
|
expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
|
@@ -16300,11 +16422,11 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
|
|
16300
16422
|
first_node = parse_pattern_keyword_rest(parser, captures);
|
16301
16423
|
break;
|
16302
16424
|
case PM_TOKEN_STRING_BEGIN:
|
16303
|
-
first_node = parse_expression(parser, PM_BINDING_POWER_MAX, false,
|
16425
|
+
first_node = parse_expression(parser, PM_BINDING_POWER_MAX, false, PM_ERR_PATTERN_HASH_KEY_LABEL);
|
16304
16426
|
break;
|
16305
16427
|
default: {
|
16428
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_type_human(parser->current.type));
|
16306
16429
|
parser_lex(parser);
|
16307
|
-
pm_parser_err_previous(parser, PM_ERR_PATTERN_HASH_KEY);
|
16308
16430
|
|
16309
16431
|
first_node = (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
|
16310
16432
|
break;
|
@@ -16506,7 +16628,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
|
|
16506
16628
|
pm_token_t opening = parser->current;
|
16507
16629
|
parser_lex(parser);
|
16508
16630
|
|
16509
|
-
pm_node_t *body = parse_pattern(parser, captures,
|
16631
|
+
pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN);
|
16510
16632
|
accept1(parser, PM_TOKEN_NEWLINE);
|
16511
16633
|
expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
|
16512
16634
|
pm_node_t *right = (pm_node_t *) pm_parentheses_node_create(parser, &opening, body, &parser->previous);
|
@@ -16565,7 +16687,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
|
|
16565
16687
|
* Parse a pattern matching expression.
|
16566
16688
|
*/
|
16567
16689
|
static pm_node_t *
|
16568
|
-
parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures,
|
16690
|
+
parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flags, pm_diagnostic_id_t diag_id) {
|
16569
16691
|
pm_node_t *node = NULL;
|
16570
16692
|
|
16571
16693
|
bool leading_rest = false;
|
@@ -16575,14 +16697,26 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, bool top_pat
|
|
16575
16697
|
case PM_TOKEN_LABEL: {
|
16576
16698
|
parser_lex(parser);
|
16577
16699
|
pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
|
16578
|
-
|
16700
|
+
node = (pm_node_t *) parse_pattern_hash(parser, captures, key);
|
16701
|
+
|
16702
|
+
if (!(flags & PM_PARSE_PATTERN_TOP)) {
|
16703
|
+
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
|
16704
|
+
}
|
16705
|
+
|
16706
|
+
return node;
|
16579
16707
|
}
|
16580
16708
|
case PM_TOKEN_USTAR_STAR: {
|
16581
16709
|
node = parse_pattern_keyword_rest(parser, captures);
|
16582
|
-
|
16710
|
+
node = (pm_node_t *) parse_pattern_hash(parser, captures, node);
|
16711
|
+
|
16712
|
+
if (!(flags & PM_PARSE_PATTERN_TOP)) {
|
16713
|
+
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
|
16714
|
+
}
|
16715
|
+
|
16716
|
+
return node;
|
16583
16717
|
}
|
16584
16718
|
case PM_TOKEN_USTAR: {
|
16585
|
-
if (
|
16719
|
+
if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
|
16586
16720
|
parser_lex(parser);
|
16587
16721
|
node = (pm_node_t *) parse_pattern_rest(parser, captures);
|
16588
16722
|
leading_rest = true;
|
@@ -16601,7 +16735,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, bool top_pat
|
|
16601
16735
|
return (pm_node_t *) parse_pattern_hash(parser, captures, node);
|
16602
16736
|
}
|
16603
16737
|
|
16604
|
-
if (
|
16738
|
+
if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
|
16605
16739
|
// If we have a comma, then we are now parsing either an array pattern or a
|
16606
16740
|
// find pattern. We need to parse all of the patterns, put them into a big
|
16607
16741
|
// list, and then determine which type of node we have.
|
@@ -16912,6 +17046,11 @@ pm_parser_err_prefix(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
|
|
16912
17046
|
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, diag_id, pm_token_type_human(parser->previous.type));
|
16913
17047
|
break;
|
16914
17048
|
}
|
17049
|
+
case PM_ERR_HASH_VALUE:
|
17050
|
+
case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
|
17051
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, diag_id, pm_token_type_human(parser->current.type));
|
17052
|
+
break;
|
17053
|
+
}
|
16915
17054
|
case PM_ERR_UNARY_RECEIVER: {
|
16916
17055
|
const char *human = (parser->current.type == PM_TOKEN_EOF ? "end-of-input" : pm_token_type_human(parser->current.type));
|
16917
17056
|
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, diag_id, human, parser->previous.start[0]);
|
@@ -17887,7 +18026,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
17887
18026
|
pm_token_t in_keyword = parser->previous;
|
17888
18027
|
|
17889
18028
|
pm_constant_id_list_t captures = { 0 };
|
17890
|
-
pm_node_t *pattern = parse_pattern(parser, &captures,
|
18029
|
+
pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN);
|
17891
18030
|
|
17892
18031
|
parser->pattern_matching_newlines = previous_pattern_matching_newlines;
|
17893
18032
|
pm_constant_id_list_free(&captures);
|
@@ -17916,7 +18055,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
17916
18055
|
then_keyword = not_provided(parser);
|
17917
18056
|
}
|
17918
18057
|
} else {
|
17919
|
-
expect1(parser, PM_TOKEN_KEYWORD_THEN,
|
18058
|
+
expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
|
17920
18059
|
then_keyword = parser->previous;
|
17921
18060
|
}
|
17922
18061
|
|
@@ -18370,7 +18509,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
18370
18509
|
lex_state_set(parser, PM_LEX_STATE_BEG);
|
18371
18510
|
parser->command_start = true;
|
18372
18511
|
|
18373
|
-
|
18512
|
+
if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
|
18513
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_type_human(parser->current.type));
|
18514
|
+
parser->previous.start = parser->previous.end;
|
18515
|
+
parser->previous.type = PM_TOKEN_MISSING;
|
18516
|
+
}
|
18517
|
+
|
18374
18518
|
rparen = parser->previous;
|
18375
18519
|
break;
|
18376
18520
|
}
|
@@ -19219,6 +19363,14 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
19219
19363
|
pm_token_t opening = not_provided(parser);
|
19220
19364
|
pm_token_t closing = not_provided(parser);
|
19221
19365
|
pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &parser->previous, &closing, &unescaped);
|
19366
|
+
|
19367
|
+
if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
|
19368
|
+
// This is extremely strange, but the first string part of a
|
19369
|
+
// regular expression will always be tagged as binary if we
|
19370
|
+
// are in a US-ASCII file, no matter its contents.
|
19371
|
+
pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
|
19372
|
+
}
|
19373
|
+
|
19222
19374
|
pm_interpolated_regular_expression_node_append(interpolated, part);
|
19223
19375
|
} else {
|
19224
19376
|
// If the first part of the body of the regular expression is not a
|
@@ -19692,39 +19844,6 @@ parse_call_operator_write(pm_parser_t *parser, pm_call_node_t *call_node, const
|
|
19692
19844
|
}
|
19693
19845
|
}
|
19694
19846
|
|
19695
|
-
/**
|
19696
|
-
* Returns true if the name of the capture group is a valid local variable that
|
19697
|
-
* can be written to.
|
19698
|
-
*/
|
19699
|
-
static bool
|
19700
|
-
parse_regular_expression_named_capture(pm_parser_t *parser, const uint8_t *source, size_t length) {
|
19701
|
-
if (length == 0) {
|
19702
|
-
return false;
|
19703
|
-
}
|
19704
|
-
|
19705
|
-
// First ensure that it starts with a valid identifier starting character.
|
19706
|
-
size_t width = char_is_identifier_start(parser, source);
|
19707
|
-
if (!width) {
|
19708
|
-
return false;
|
19709
|
-
}
|
19710
|
-
|
19711
|
-
// Next, ensure that it's not an uppercase character.
|
19712
|
-
if (parser->encoding_changed) {
|
19713
|
-
if (parser->encoding->isupper_char(source, (ptrdiff_t) length)) return false;
|
19714
|
-
} else {
|
19715
|
-
if (pm_encoding_utf_8_isupper_char(source, (ptrdiff_t) length)) return false;
|
19716
|
-
}
|
19717
|
-
|
19718
|
-
// Next, iterate through all of the bytes of the string to ensure that they
|
19719
|
-
// are all valid identifier characters.
|
19720
|
-
const uint8_t *cursor = source + width;
|
19721
|
-
while (cursor < source + length && (width = char_is_identifier(parser, cursor))) {
|
19722
|
-
cursor += width;
|
19723
|
-
}
|
19724
|
-
|
19725
|
-
return cursor == source + length;
|
19726
|
-
}
|
19727
|
-
|
19728
19847
|
/**
|
19729
19848
|
* Potentially change a =~ with a regular expression with named captures into a
|
19730
19849
|
* match write node.
|
@@ -19751,7 +19870,7 @@ parse_regular_expression_named_captures(pm_parser_t *parser, const pm_string_t *
|
|
19751
19870
|
|
19752
19871
|
// If the name of the capture group isn't a valid identifier, we do
|
19753
19872
|
// not add it to the local table.
|
19754
|
-
if (!
|
19873
|
+
if (!pm_slice_is_valid_local(parser, source, source + length)) continue;
|
19755
19874
|
|
19756
19875
|
if (content->type == PM_STRING_SHARED) {
|
19757
19876
|
// If the unescaped string is a slice of the source, then we can
|
@@ -20209,7 +20328,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
|
|
20209
20328
|
// In this case we have an operator but we don't know what it's for.
|
20210
20329
|
// We need to treat it as an error. For now, we'll mark it as an error
|
20211
20330
|
// and just skip right past it.
|
20212
|
-
|
20331
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_type_human(parser->current.type));
|
20213
20332
|
return node;
|
20214
20333
|
}
|
20215
20334
|
}
|
@@ -20591,7 +20710,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
|
|
20591
20710
|
parser_lex(parser);
|
20592
20711
|
|
20593
20712
|
pm_constant_id_list_t captures = { 0 };
|
20594
|
-
pm_node_t *pattern = parse_pattern(parser, &captures,
|
20713
|
+
pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN);
|
20595
20714
|
|
20596
20715
|
parser->pattern_matching_newlines = previous_pattern_matching_newlines;
|
20597
20716
|
pm_constant_id_list_free(&captures);
|
@@ -20608,7 +20727,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
|
|
20608
20727
|
parser_lex(parser);
|
20609
20728
|
|
20610
20729
|
pm_constant_id_list_t captures = { 0 };
|
20611
|
-
pm_node_t *pattern = parse_pattern(parser, &captures,
|
20730
|
+
pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET);
|
20612
20731
|
|
20613
20732
|
parser->pattern_matching_newlines = previous_pattern_matching_newlines;
|
20614
20733
|
pm_constant_id_list_free(&captures);
|
@@ -20621,6 +20740,10 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
|
|
20621
20740
|
}
|
20622
20741
|
}
|
20623
20742
|
|
20743
|
+
#undef PM_PARSE_PATTERN_SINGLE
|
20744
|
+
#undef PM_PARSE_PATTERN_TOP
|
20745
|
+
#undef PM_PARSE_PATTERN_MULTI
|
20746
|
+
|
20624
20747
|
/**
|
20625
20748
|
* Parse an expression at the given point of the parser using the given binding
|
20626
20749
|
* power to parse subsequent chains. If this function finds a syntax error, it
|