prism 1.4.0 → 1.5.1
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 +30 -1
- data/Makefile +2 -1
- data/README.md +1 -0
- data/config.yml +264 -37
- data/docs/parser_translation.md +8 -23
- data/docs/ripper_translation.md +1 -1
- data/ext/prism/api_node.c +2 -0
- data/ext/prism/extension.c +14 -1
- data/ext/prism/extension.h +1 -1
- data/include/prism/ast.h +275 -49
- data/include/prism/diagnostic.h +4 -0
- data/include/prism/options.h +43 -3
- data/include/prism/regexp.h +2 -2
- data/include/prism/util/pm_buffer.h +8 -0
- data/include/prism/util/pm_integer.h +4 -0
- data/include/prism/util/pm_list.h +6 -0
- data/include/prism/util/pm_string.h +12 -2
- data/include/prism/version.h +3 -3
- data/include/prism.h +39 -14
- data/lib/prism/compiler.rb +456 -151
- data/lib/prism/desugar_compiler.rb +1 -0
- data/lib/prism/dispatcher.rb +16 -0
- data/lib/prism/dot_visitor.rb +5 -1
- data/lib/prism/dsl.rb +3 -0
- data/lib/prism/ffi.rb +17 -7
- data/lib/prism/inspect_visitor.rb +3 -0
- data/lib/prism/lex_compat.rb +1 -0
- data/lib/prism/mutation_compiler.rb +3 -0
- data/lib/prism/node.rb +506 -335
- data/lib/prism/node_ext.rb +4 -1
- data/lib/prism/pack.rb +2 -0
- data/lib/prism/parse_result/comments.rb +1 -0
- data/lib/prism/parse_result/errors.rb +1 -0
- data/lib/prism/parse_result/newlines.rb +1 -0
- data/lib/prism/parse_result.rb +1 -0
- data/lib/prism/pattern.rb +1 -0
- data/lib/prism/polyfill/scan_byte.rb +14 -0
- data/lib/prism/polyfill/warn.rb +42 -0
- data/lib/prism/reflection.rb +3 -0
- data/lib/prism/relocation.rb +1 -0
- data/lib/prism/serialize.rb +25 -20
- data/lib/prism/string_query.rb +1 -0
- data/lib/prism/translation/parser/builder.rb +1 -0
- data/lib/prism/translation/parser/compiler.rb +47 -25
- data/lib/prism/translation/parser/lexer.rb +29 -21
- data/lib/prism/translation/parser.rb +13 -1
- data/lib/prism/translation/parser33.rb +1 -0
- data/lib/prism/translation/parser34.rb +1 -0
- data/lib/prism/translation/parser35.rb +1 -0
- data/lib/prism/translation/parser_current.rb +24 -0
- data/lib/prism/translation/ripper/sexp.rb +1 -0
- data/lib/prism/translation/ripper.rb +17 -1
- data/lib/prism/translation/ruby_parser.rb +286 -3
- data/lib/prism/translation.rb +2 -0
- data/lib/prism/visitor.rb +457 -152
- data/lib/prism.rb +2 -0
- data/prism.gemspec +5 -1
- data/rbi/prism/dsl.rbi +3 -3
- data/rbi/prism/node.rbi +21 -9
- data/sig/prism/dispatcher.rbs +3 -0
- data/sig/prism/dsl.rbs +3 -3
- data/sig/prism/node.rbs +444 -30
- data/sig/prism/node_ext.rbs +84 -17
- data/sig/prism/parse_result/comments.rbs +38 -0
- data/sig/prism/parse_result.rbs +4 -0
- data/sig/prism/reflection.rbs +1 -1
- data/src/diagnostic.c +7 -1
- data/src/node.c +2 -0
- data/src/options.c +2 -2
- data/src/prettyprint.c +2 -0
- data/src/prism.c +248 -130
- data/src/serialize.c +2 -0
- data/src/token_type.c +36 -34
- metadata +6 -2
data/src/prism.c
CHANGED
@@ -1409,7 +1409,7 @@ pm_conditional_predicate_warn_write_literal_p(const pm_node_t *node) {
|
|
1409
1409
|
static inline void
|
1410
1410
|
pm_conditional_predicate_warn_write_literal(pm_parser_t *parser, const pm_node_t *node) {
|
1411
1411
|
if (pm_conditional_predicate_warn_write_literal_p(node)) {
|
1412
|
-
pm_parser_warn_node(parser, node, parser->version
|
1412
|
+
pm_parser_warn_node(parser, node, parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_WARN_EQUAL_IN_CONDITIONAL_3_3 : PM_WARN_EQUAL_IN_CONDITIONAL);
|
1413
1413
|
}
|
1414
1414
|
}
|
1415
1415
|
|
@@ -2976,7 +2976,7 @@ pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
|
|
2976
2976
|
*/
|
2977
2977
|
static void
|
2978
2978
|
pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
|
2979
|
-
if (parser->version
|
2979
|
+
if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
|
2980
2980
|
if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
|
2981
2981
|
pm_node_t *node;
|
2982
2982
|
PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
|
@@ -3874,7 +3874,7 @@ pm_def_node_create(
|
|
3874
3874
|
end = end_keyword->end;
|
3875
3875
|
}
|
3876
3876
|
|
3877
|
-
if (
|
3877
|
+
if (receiver != NULL) {
|
3878
3878
|
pm_def_node_receiver_check(parser, receiver);
|
3879
3879
|
}
|
3880
3880
|
|
@@ -4253,7 +4253,7 @@ pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
|
|
4253
4253
|
const uint8_t *point = memchr(start, '.', length);
|
4254
4254
|
assert(point && "should have a decimal point");
|
4255
4255
|
|
4256
|
-
uint8_t *digits =
|
4256
|
+
uint8_t *digits = xmalloc(length);
|
4257
4257
|
if (digits == NULL) {
|
4258
4258
|
fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
|
4259
4259
|
abort();
|
@@ -4266,7 +4266,7 @@ pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
|
|
4266
4266
|
digits[0] = '1';
|
4267
4267
|
if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
|
4268
4268
|
pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
|
4269
|
-
|
4269
|
+
xfree(digits);
|
4270
4270
|
|
4271
4271
|
pm_integers_reduce(&node->numerator, &node->denominator);
|
4272
4272
|
return node;
|
@@ -8582,85 +8582,66 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
|
|
8582
8582
|
/* Context manipulations */
|
8583
8583
|
/******************************************************************************/
|
8584
8584
|
|
8585
|
-
static
|
8586
|
-
|
8587
|
-
|
8588
|
-
|
8589
|
-
|
8590
|
-
|
8591
|
-
|
8592
|
-
|
8593
|
-
|
8594
|
-
|
8595
|
-
|
8596
|
-
|
8597
|
-
|
8598
|
-
|
8599
|
-
|
8600
|
-
|
8601
|
-
|
8602
|
-
|
8603
|
-
|
8604
|
-
|
8605
|
-
|
8606
|
-
|
8607
|
-
|
8608
|
-
|
8609
|
-
|
8610
|
-
|
8611
|
-
|
8612
|
-
|
8613
|
-
|
8614
|
-
|
8615
|
-
|
8616
|
-
|
8617
|
-
|
8618
|
-
|
8619
|
-
|
8620
|
-
|
8621
|
-
|
8622
|
-
|
8623
|
-
|
8624
|
-
|
8625
|
-
|
8626
|
-
|
8627
|
-
|
8628
|
-
|
8629
|
-
|
8630
|
-
|
8631
|
-
|
8632
|
-
|
8633
|
-
|
8634
|
-
|
8635
|
-
|
8636
|
-
|
8637
|
-
|
8638
|
-
|
8639
|
-
|
8640
|
-
|
8641
|
-
case PM_CONTEXT_CLASS_RESCUE:
|
8642
|
-
case PM_CONTEXT_DEF_RESCUE:
|
8643
|
-
case PM_CONTEXT_LAMBDA_RESCUE:
|
8644
|
-
case PM_CONTEXT_MODULE_RESCUE:
|
8645
|
-
case PM_CONTEXT_SCLASS_RESCUE:
|
8646
|
-
return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_RESCUE || token->type == PM_TOKEN_KEYWORD_ELSE || token->type == PM_TOKEN_KEYWORD_END;
|
8647
|
-
case PM_CONTEXT_BEGIN_ELSE:
|
8648
|
-
case PM_CONTEXT_BLOCK_ELSE:
|
8649
|
-
case PM_CONTEXT_CLASS_ELSE:
|
8650
|
-
case PM_CONTEXT_DEF_ELSE:
|
8651
|
-
case PM_CONTEXT_LAMBDA_ELSE:
|
8652
|
-
case PM_CONTEXT_MODULE_ELSE:
|
8653
|
-
case PM_CONTEXT_SCLASS_ELSE:
|
8654
|
-
return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_END;
|
8655
|
-
case PM_CONTEXT_LAMBDA_BRACES:
|
8656
|
-
return token->type == PM_TOKEN_BRACE_RIGHT;
|
8657
|
-
case PM_CONTEXT_PREDICATE:
|
8658
|
-
return token->type == PM_TOKEN_KEYWORD_THEN || token->type == PM_TOKEN_NEWLINE || token->type == PM_TOKEN_SEMICOLON;
|
8659
|
-
case PM_CONTEXT_NONE:
|
8660
|
-
return false;
|
8661
|
-
}
|
8585
|
+
static const uint32_t context_terminators[] = {
|
8586
|
+
[PM_CONTEXT_NONE] = 0,
|
8587
|
+
[PM_CONTEXT_BEGIN] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8588
|
+
[PM_CONTEXT_BEGIN_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8589
|
+
[PM_CONTEXT_BEGIN_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8590
|
+
[PM_CONTEXT_BEGIN_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8591
|
+
[PM_CONTEXT_BLOCK_BRACES] = (1 << PM_TOKEN_BRACE_RIGHT),
|
8592
|
+
[PM_CONTEXT_BLOCK_KEYWORDS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
8593
|
+
[PM_CONTEXT_BLOCK_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8594
|
+
[PM_CONTEXT_BLOCK_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8595
|
+
[PM_CONTEXT_BLOCK_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8596
|
+
[PM_CONTEXT_CASE_WHEN] = (1 << PM_TOKEN_KEYWORD_WHEN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
|
8597
|
+
[PM_CONTEXT_CASE_IN] = (1 << PM_TOKEN_KEYWORD_IN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
|
8598
|
+
[PM_CONTEXT_CLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
8599
|
+
[PM_CONTEXT_CLASS_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8600
|
+
[PM_CONTEXT_CLASS_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8601
|
+
[PM_CONTEXT_CLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8602
|
+
[PM_CONTEXT_DEF] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
8603
|
+
[PM_CONTEXT_DEF_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8604
|
+
[PM_CONTEXT_DEF_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8605
|
+
[PM_CONTEXT_DEF_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8606
|
+
[PM_CONTEXT_DEF_PARAMS] = (1 << PM_TOKEN_EOF),
|
8607
|
+
[PM_CONTEXT_DEFINED] = (1 << PM_TOKEN_EOF),
|
8608
|
+
[PM_CONTEXT_DEFAULT_PARAMS] = (1 << PM_TOKEN_COMMA) | (1 << PM_TOKEN_PARENTHESIS_RIGHT),
|
8609
|
+
[PM_CONTEXT_ELSE] = (1 << PM_TOKEN_KEYWORD_END),
|
8610
|
+
[PM_CONTEXT_ELSIF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
|
8611
|
+
[PM_CONTEXT_EMBEXPR] = (1 << PM_TOKEN_EMBEXPR_END),
|
8612
|
+
[PM_CONTEXT_FOR] = (1 << PM_TOKEN_KEYWORD_END),
|
8613
|
+
[PM_CONTEXT_FOR_INDEX] = (1 << PM_TOKEN_KEYWORD_IN),
|
8614
|
+
[PM_CONTEXT_IF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
|
8615
|
+
[PM_CONTEXT_LAMBDA_BRACES] = (1 << PM_TOKEN_BRACE_RIGHT),
|
8616
|
+
[PM_CONTEXT_LAMBDA_DO_END] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
8617
|
+
[PM_CONTEXT_LAMBDA_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8618
|
+
[PM_CONTEXT_LAMBDA_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8619
|
+
[PM_CONTEXT_LAMBDA_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8620
|
+
[PM_CONTEXT_LOOP_PREDICATE] = (1 << PM_TOKEN_KEYWORD_DO) | (1 << PM_TOKEN_KEYWORD_THEN),
|
8621
|
+
[PM_CONTEXT_MAIN] = (1 << PM_TOKEN_EOF),
|
8622
|
+
[PM_CONTEXT_MODULE] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
8623
|
+
[PM_CONTEXT_MODULE_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8624
|
+
[PM_CONTEXT_MODULE_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8625
|
+
[PM_CONTEXT_MODULE_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8626
|
+
[PM_CONTEXT_MULTI_TARGET] = (1 << PM_TOKEN_EOF),
|
8627
|
+
[PM_CONTEXT_PARENS] = (1 << PM_TOKEN_PARENTHESIS_RIGHT),
|
8628
|
+
[PM_CONTEXT_POSTEXE] = (1 << PM_TOKEN_BRACE_RIGHT),
|
8629
|
+
[PM_CONTEXT_PREDICATE] = (1 << PM_TOKEN_KEYWORD_THEN) | (1 << PM_TOKEN_NEWLINE) | (1 << PM_TOKEN_SEMICOLON),
|
8630
|
+
[PM_CONTEXT_PREEXE] = (1 << PM_TOKEN_BRACE_RIGHT),
|
8631
|
+
[PM_CONTEXT_RESCUE_MODIFIER] = (1 << PM_TOKEN_EOF),
|
8632
|
+
[PM_CONTEXT_SCLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
8633
|
+
[PM_CONTEXT_SCLASS_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8634
|
+
[PM_CONTEXT_SCLASS_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8635
|
+
[PM_CONTEXT_SCLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8636
|
+
[PM_CONTEXT_TERNARY] = (1 << PM_TOKEN_EOF),
|
8637
|
+
[PM_CONTEXT_UNLESS] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8638
|
+
[PM_CONTEXT_UNTIL] = (1 << PM_TOKEN_KEYWORD_END),
|
8639
|
+
[PM_CONTEXT_WHILE] = (1 << PM_TOKEN_KEYWORD_END),
|
8640
|
+
};
|
8662
8641
|
|
8663
|
-
|
8642
|
+
static inline bool
|
8643
|
+
context_terminator(pm_context_t context, pm_token_t *token) {
|
8644
|
+
return token->type < 32 && (context_terminators[context] & (1 << token->type));
|
8664
8645
|
}
|
8665
8646
|
|
8666
8647
|
/**
|
@@ -9109,7 +9090,7 @@ lex_global_variable(pm_parser_t *parser) {
|
|
9109
9090
|
} while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
|
9110
9091
|
|
9111
9092
|
// $0 isn't allowed to be followed by anything.
|
9112
|
-
pm_diagnostic_id_t diag_id = parser->version
|
9093
|
+
pm_diagnostic_id_t diag_id = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
|
9113
9094
|
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, diag_id);
|
9114
9095
|
}
|
9115
9096
|
|
@@ -9146,7 +9127,7 @@ lex_global_variable(pm_parser_t *parser) {
|
|
9146
9127
|
} else {
|
9147
9128
|
// If we get here, then we have a $ followed by something that
|
9148
9129
|
// isn't recognized as a global variable.
|
9149
|
-
pm_diagnostic_id_t diag_id = parser->version
|
9130
|
+
pm_diagnostic_id_t diag_id = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
|
9150
9131
|
const uint8_t *end = parser->current.end + parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
|
9151
9132
|
PM_PARSER_ERR_FORMAT(parser, parser->current.start, end, diag_id, (int) (end - parser->current.start), (const char *) parser->current.start);
|
9152
9133
|
}
|
@@ -10173,7 +10154,7 @@ lex_at_variable(pm_parser_t *parser) {
|
|
10173
10154
|
}
|
10174
10155
|
} else if (parser->current.end < end && pm_char_is_decimal_digit(*parser->current.end)) {
|
10175
10156
|
pm_diagnostic_id_t diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
|
10176
|
-
if (parser->version
|
10157
|
+
if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) {
|
10177
10158
|
diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
|
10178
10159
|
}
|
10179
10160
|
|
@@ -10849,14 +10830,37 @@ parser_lex(pm_parser_t *parser) {
|
|
10849
10830
|
following = next_newline(following, parser->end - following);
|
10850
10831
|
}
|
10851
10832
|
|
10852
|
-
// If the lex state was ignored,
|
10853
|
-
//
|
10833
|
+
// If the lex state was ignored, we will lex the
|
10834
|
+
// ignored newline.
|
10835
|
+
if (lex_state_ignored_p(parser)) {
|
10836
|
+
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10837
|
+
lexed_comment = false;
|
10838
|
+
goto lex_next_token;
|
10839
|
+
}
|
10840
|
+
|
10841
|
+
// If we hit a '.' or a '&.' we will lex the ignored
|
10842
|
+
// newline.
|
10843
|
+
if (following && (
|
10844
|
+
(peek_at(parser, following) == '.') ||
|
10845
|
+
(peek_at(parser, following) == '&' && peek_at(parser, following + 1) == '.')
|
10846
|
+
)) {
|
10847
|
+
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10848
|
+
lexed_comment = false;
|
10849
|
+
goto lex_next_token;
|
10850
|
+
}
|
10851
|
+
|
10852
|
+
|
10853
|
+
// If we are parsing as CRuby 3.5 or later and we
|
10854
|
+
// hit a '&&' or a '||' then we will lex the ignored
|
10855
|
+
// newline.
|
10854
10856
|
if (
|
10855
|
-
|
10856
|
-
|
10857
|
-
(peek_at(parser, following) == '
|
10858
|
-
(peek_at(parser, following) == '
|
10859
|
-
|
10857
|
+
(parser->version >= PM_OPTIONS_VERSION_CRUBY_3_5) &&
|
10858
|
+
following && (
|
10859
|
+
(peek_at(parser, following) == '&' && peek_at(parser, following + 1) == '&') ||
|
10860
|
+
(peek_at(parser, following) == '|' && peek_at(parser, following + 1) == '|') ||
|
10861
|
+
(peek_at(parser, following) == 'a' && peek_at(parser, following + 1) == 'n' && peek_at(parser, following + 2) == 'd' && !char_is_identifier(parser, following + 3, parser->end - (following + 3))) ||
|
10862
|
+
(peek_at(parser, following) == 'o' && peek_at(parser, following + 1) == 'r' && !char_is_identifier(parser, following + 2, parser->end - (following + 2)))
|
10863
|
+
)
|
10860
10864
|
) {
|
10861
10865
|
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10862
10866
|
lexed_comment = false;
|
@@ -10896,6 +10900,63 @@ parser_lex(pm_parser_t *parser) {
|
|
10896
10900
|
parser->next_start = NULL;
|
10897
10901
|
LEX(PM_TOKEN_AMPERSAND_DOT);
|
10898
10902
|
}
|
10903
|
+
|
10904
|
+
if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_5) {
|
10905
|
+
// If we hit an && then we are in a logical chain
|
10906
|
+
// and we need to return the logical operator.
|
10907
|
+
if (peek_at(parser, next_content) == '&' && peek_at(parser, next_content + 1) == '&') {
|
10908
|
+
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10909
|
+
lex_state_set(parser, PM_LEX_STATE_BEG);
|
10910
|
+
parser->current.start = next_content;
|
10911
|
+
parser->current.end = next_content + 2;
|
10912
|
+
parser->next_start = NULL;
|
10913
|
+
LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
|
10914
|
+
}
|
10915
|
+
|
10916
|
+
// If we hit a || then we are in a logical chain and
|
10917
|
+
// we need to return the logical operator.
|
10918
|
+
if (peek_at(parser, next_content) == '|' && peek_at(parser, next_content + 1) == '|') {
|
10919
|
+
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10920
|
+
lex_state_set(parser, PM_LEX_STATE_BEG);
|
10921
|
+
parser->current.start = next_content;
|
10922
|
+
parser->current.end = next_content + 2;
|
10923
|
+
parser->next_start = NULL;
|
10924
|
+
LEX(PM_TOKEN_PIPE_PIPE);
|
10925
|
+
}
|
10926
|
+
|
10927
|
+
// If we hit an 'and' then we are in a logical chain
|
10928
|
+
// and we need to return the logical operator.
|
10929
|
+
if (
|
10930
|
+
peek_at(parser, next_content) == 'a' &&
|
10931
|
+
peek_at(parser, next_content + 1) == 'n' &&
|
10932
|
+
peek_at(parser, next_content + 2) == 'd' &&
|
10933
|
+
!char_is_identifier(parser, next_content + 3, parser->end - (next_content + 3))
|
10934
|
+
) {
|
10935
|
+
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10936
|
+
lex_state_set(parser, PM_LEX_STATE_BEG);
|
10937
|
+
parser->current.start = next_content;
|
10938
|
+
parser->current.end = next_content + 3;
|
10939
|
+
parser->next_start = NULL;
|
10940
|
+
parser->command_start = true;
|
10941
|
+
LEX(PM_TOKEN_KEYWORD_AND);
|
10942
|
+
}
|
10943
|
+
|
10944
|
+
// If we hit a 'or' then we are in a logical chain
|
10945
|
+
// and we need to return the logical operator.
|
10946
|
+
if (
|
10947
|
+
peek_at(parser, next_content) == 'o' &&
|
10948
|
+
peek_at(parser, next_content + 1) == 'r' &&
|
10949
|
+
!char_is_identifier(parser, next_content + 2, parser->end - (next_content + 2))
|
10950
|
+
) {
|
10951
|
+
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10952
|
+
lex_state_set(parser, PM_LEX_STATE_BEG);
|
10953
|
+
parser->current.start = next_content;
|
10954
|
+
parser->current.end = next_content + 2;
|
10955
|
+
parser->next_start = NULL;
|
10956
|
+
parser->command_start = true;
|
10957
|
+
LEX(PM_TOKEN_KEYWORD_OR);
|
10958
|
+
}
|
10959
|
+
}
|
10899
10960
|
}
|
10900
10961
|
|
10901
10962
|
// At this point we know this is a regular newline, and we can set the
|
@@ -13142,14 +13203,6 @@ match8(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2,
|
|
13142
13203
|
return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7) || match1(parser, type8);
|
13143
13204
|
}
|
13144
13205
|
|
13145
|
-
/**
|
13146
|
-
* Returns true if the current token is any of the nine given types.
|
13147
|
-
*/
|
13148
|
-
static inline bool
|
13149
|
-
match9(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6, pm_token_type_t type7, pm_token_type_t type8, pm_token_type_t type9) {
|
13150
|
-
return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7) || match1(parser, type8) || match1(parser, type9);
|
13151
|
-
}
|
13152
|
-
|
13153
13206
|
/**
|
13154
13207
|
* If the current token is of the specified type, lex forward by one token and
|
13155
13208
|
* return true. Otherwise, return false. For example:
|
@@ -14671,7 +14724,7 @@ parse_parameters(
|
|
14671
14724
|
parser_lex(parser);
|
14672
14725
|
|
14673
14726
|
pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &name);
|
14674
|
-
uint32_t reads = parser->version
|
14727
|
+
uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
|
14675
14728
|
|
14676
14729
|
if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser, true);
|
14677
14730
|
pm_node_t *value = parse_value_expression(parser, binding_power, false, false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
|
@@ -14687,7 +14740,7 @@ parse_parameters(
|
|
14687
14740
|
// If the value of the parameter increased the number of
|
14688
14741
|
// reads of that parameter, then we need to warn that we
|
14689
14742
|
// have a circular definition.
|
14690
|
-
if ((parser->version
|
14743
|
+
if ((parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
|
14691
14744
|
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
|
14692
14745
|
}
|
14693
14746
|
|
@@ -14772,13 +14825,13 @@ parse_parameters(
|
|
14772
14825
|
|
14773
14826
|
if (token_begins_expression_p(parser->current.type)) {
|
14774
14827
|
pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &local);
|
14775
|
-
uint32_t reads = parser->version
|
14828
|
+
uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
|
14776
14829
|
|
14777
14830
|
if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser, true);
|
14778
14831
|
pm_node_t *value = parse_value_expression(parser, binding_power, false, false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
|
14779
14832
|
if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
|
14780
14833
|
|
14781
|
-
if (parser->version
|
14834
|
+
if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
|
14782
14835
|
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
|
14783
14836
|
}
|
14784
14837
|
|
@@ -16482,7 +16535,7 @@ parse_variable(pm_parser_t *parser) {
|
|
16482
16535
|
pm_node_list_append(¤t_scope->implicit_parameters, node);
|
16483
16536
|
|
16484
16537
|
return node;
|
16485
|
-
} else if ((parser->version
|
16538
|
+
} else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.start, parser->previous.end)) {
|
16486
16539
|
pm_node_t *node = (pm_node_t *) pm_it_local_variable_read_node_create(parser, &parser->previous);
|
16487
16540
|
pm_node_list_append(¤t_scope->implicit_parameters, node);
|
16488
16541
|
|
@@ -17412,6 +17465,14 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
|
|
17412
17465
|
// If we found a label, we need to immediately return to the caller.
|
17413
17466
|
if (pm_symbol_node_label_p(node)) return node;
|
17414
17467
|
|
17468
|
+
// Call nodes (arithmetic operations) are not allowed in patterns
|
17469
|
+
if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
|
17470
|
+
pm_parser_err_node(parser, node, diag_id);
|
17471
|
+
pm_missing_node_t *missing_node = pm_missing_node_create(parser, node->location.start, node->location.end);
|
17472
|
+
pm_node_destroy(parser, node);
|
17473
|
+
return (pm_node_t *) missing_node;
|
17474
|
+
}
|
17475
|
+
|
17415
17476
|
// Now that we have a primitive, we need to check if it's part of a range.
|
17416
17477
|
if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
|
17417
17478
|
pm_token_t operator = parser->previous;
|
@@ -17694,7 +17755,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
|
|
17694
17755
|
// Gather up all of the patterns into the list.
|
17695
17756
|
while (accept1(parser, PM_TOKEN_COMMA)) {
|
17696
17757
|
// Break early here in case we have a trailing comma.
|
17697
|
-
if (
|
17758
|
+
if (match7(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_AND, PM_TOKEN_KEYWORD_OR)) {
|
17698
17759
|
node = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
|
17699
17760
|
pm_node_list_append(&nodes, node);
|
17700
17761
|
trailing_rest = true;
|
@@ -18585,17 +18646,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
18585
18646
|
call->closing_loc = arguments.closing_loc;
|
18586
18647
|
call->block = arguments.block;
|
18587
18648
|
|
18588
|
-
|
18589
|
-
|
18590
|
-
|
18591
|
-
if (arguments.arguments != NULL) {
|
18592
|
-
call->base.location.end = arguments.arguments->base.location.end;
|
18593
|
-
} else {
|
18594
|
-
call->base.location.end = call->message_loc.end;
|
18595
|
-
}
|
18596
|
-
} else {
|
18597
|
-
call->base.location.end = arguments.closing_loc.end;
|
18649
|
+
const uint8_t *end = pm_arguments_end(&arguments);
|
18650
|
+
if (!end) {
|
18651
|
+
end = call->message_loc.end;
|
18598
18652
|
}
|
18653
|
+
call->base.location.end = end;
|
18599
18654
|
}
|
18600
18655
|
} else {
|
18601
18656
|
// Otherwise, we know the identifier is in the local table. This
|
@@ -19123,7 +19178,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
19123
19178
|
pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].left;
|
19124
19179
|
|
19125
19180
|
if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
|
19181
|
+
pm_token_t next = parser->current;
|
19126
19182
|
parse_arguments(parser, &arguments, false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
|
19183
|
+
|
19184
|
+
// Reject `foo && return bar`.
|
19185
|
+
if (!accepts_command_call && arguments.arguments != NULL) {
|
19186
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(next.type));
|
19187
|
+
}
|
19127
19188
|
}
|
19128
19189
|
}
|
19129
19190
|
|
@@ -19520,7 +19581,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
19520
19581
|
pm_do_loop_stack_push(parser, false);
|
19521
19582
|
statements = (pm_node_t *) pm_statements_node_create(parser);
|
19522
19583
|
|
19523
|
-
|
19584
|
+
bool allow_command_call;
|
19585
|
+
if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_5) {
|
19586
|
+
allow_command_call = accepts_command_call;
|
19587
|
+
} else {
|
19588
|
+
// Allow `def foo = puts "Hello"` but not `private def foo = puts "Hello"`
|
19589
|
+
allow_command_call = binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION;
|
19590
|
+
}
|
19591
|
+
|
19592
|
+
pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call, false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
|
19524
19593
|
|
19525
19594
|
if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
|
19526
19595
|
context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
|
@@ -19607,18 +19676,27 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
19607
19676
|
pm_token_t lparen;
|
19608
19677
|
pm_token_t rparen;
|
19609
19678
|
pm_node_t *expression;
|
19679
|
+
|
19610
19680
|
context_push(parser, PM_CONTEXT_DEFINED);
|
19681
|
+
bool newline = accept1(parser, PM_TOKEN_NEWLINE);
|
19611
19682
|
|
19612
19683
|
if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
|
19613
19684
|
lparen = parser->previous;
|
19614
|
-
expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
|
19615
19685
|
|
19616
|
-
if (parser
|
19686
|
+
if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
|
19687
|
+
expression = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0);
|
19688
|
+
lparen = not_provided(parser);
|
19617
19689
|
rparen = not_provided(parser);
|
19618
19690
|
} else {
|
19619
|
-
|
19620
|
-
|
19621
|
-
|
19691
|
+
expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
|
19692
|
+
|
19693
|
+
if (parser->recovering) {
|
19694
|
+
rparen = not_provided(parser);
|
19695
|
+
} else {
|
19696
|
+
accept1(parser, PM_TOKEN_NEWLINE);
|
19697
|
+
expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
|
19698
|
+
rparen = parser->previous;
|
19699
|
+
}
|
19622
19700
|
}
|
19623
19701
|
} else {
|
19624
19702
|
lparen = not_provided(parser);
|
@@ -19766,6 +19844,20 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
19766
19844
|
pm_arguments_t arguments = { 0 };
|
19767
19845
|
pm_node_t *receiver = NULL;
|
19768
19846
|
|
19847
|
+
// If we do not accept a command call, then we also do not accept a
|
19848
|
+
// not without parentheses. In this case we need to reject this
|
19849
|
+
// syntax.
|
19850
|
+
if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
|
19851
|
+
if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
|
19852
|
+
pm_parser_err(parser, parser->previous.end, parser->previous.end + 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
|
19853
|
+
} else {
|
19854
|
+
accept1(parser, PM_TOKEN_NEWLINE);
|
19855
|
+
pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
|
19856
|
+
}
|
19857
|
+
|
19858
|
+
return (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
|
19859
|
+
}
|
19860
|
+
|
19769
19861
|
accept1(parser, PM_TOKEN_NEWLINE);
|
19770
19862
|
|
19771
19863
|
if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
|
@@ -21167,6 +21259,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
|
|
21167
21259
|
}
|
21168
21260
|
PRISM_FALLTHROUGH
|
21169
21261
|
case PM_CASE_WRITABLE: {
|
21262
|
+
// When we have `it = value`, we need to add `it` as a local
|
21263
|
+
// variable before parsing the value, in case the value
|
21264
|
+
// references the variable.
|
21265
|
+
if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
|
21266
|
+
pm_parser_local_add_location(parser, node->location.start, node->location.end, 0);
|
21267
|
+
}
|
21268
|
+
|
21170
21269
|
parser_lex(parser);
|
21171
21270
|
pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) ? PM_BINDING_POWER_MULTI_ASSIGNMENT + 1 : binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
|
21172
21271
|
|
@@ -22160,6 +22259,12 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
|
|
22160
22259
|
) {
|
22161
22260
|
node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right, accepts_command_call, (uint16_t) (depth + 1));
|
22162
22261
|
|
22262
|
+
if (context_terminator(parser->current_context->context, &parser->current)) {
|
22263
|
+
// If this token terminates the current context, then we need to
|
22264
|
+
// stop parsing the expression, as it has become a statement.
|
22265
|
+
return node;
|
22266
|
+
}
|
22267
|
+
|
22163
22268
|
switch (PM_NODE_TYPE(node)) {
|
22164
22269
|
case PM_MULTI_WRITE_NODE:
|
22165
22270
|
// Multi-write nodes are statements, and cannot be followed by
|
@@ -22614,6 +22719,12 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
|
|
22614
22719
|
}
|
22615
22720
|
}
|
22616
22721
|
|
22722
|
+
// Now that we have established the user-provided options, check if
|
22723
|
+
// a version was given and parse as the latest version otherwise.
|
22724
|
+
if (parser->version == PM_OPTIONS_VERSION_UNSET) {
|
22725
|
+
parser->version = PM_OPTIONS_VERSION_LATEST;
|
22726
|
+
}
|
22727
|
+
|
22617
22728
|
pm_accepts_block_stack_push(parser, true);
|
22618
22729
|
|
22619
22730
|
// Skip past the UTF-8 BOM if it exists.
|
@@ -22667,7 +22778,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
|
|
22667
22778
|
}
|
22668
22779
|
|
22669
22780
|
search_shebang = false;
|
22670
|
-
} else if (options->main_script && !parser->parsing_eval) {
|
22781
|
+
} else if (options != NULL && options->main_script && !parser->parsing_eval) {
|
22671
22782
|
search_shebang = true;
|
22672
22783
|
}
|
22673
22784
|
}
|
@@ -22807,7 +22918,7 @@ pm_parse(pm_parser_t *parser) {
|
|
22807
22918
|
* otherwise return true.
|
22808
22919
|
*/
|
22809
22920
|
static bool
|
22810
|
-
pm_parse_stream_read(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets) {
|
22921
|
+
pm_parse_stream_read(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof) {
|
22811
22922
|
#define LINE_SIZE 4096
|
22812
22923
|
char line[LINE_SIZE];
|
22813
22924
|
|
@@ -22843,6 +22954,12 @@ pm_parse_stream_read(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t
|
|
22843
22954
|
if (strncmp(line, "__END__\r\n", 9) == 0) return false;
|
22844
22955
|
break;
|
22845
22956
|
}
|
22957
|
+
|
22958
|
+
// All data should be read via gets. If the string returned by gets
|
22959
|
+
// _doesn't_ end with a newline, then we assume we hit EOF condition.
|
22960
|
+
if (stream_feof(stream)) {
|
22961
|
+
break;
|
22962
|
+
}
|
22846
22963
|
}
|
22847
22964
|
|
22848
22965
|
return true;
|
@@ -22878,16 +22995,17 @@ pm_parse_stream_unterminated_heredoc_p(pm_parser_t *parser) {
|
|
22878
22995
|
* can stream stdin in to Ruby so we need to support a streaming API.
|
22879
22996
|
*/
|
22880
22997
|
PRISM_EXPORTED_FUNCTION pm_node_t *
|
22881
|
-
pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, const pm_options_t *options) {
|
22998
|
+
pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof, const pm_options_t *options) {
|
22882
22999
|
pm_buffer_init(buffer);
|
22883
23000
|
|
22884
|
-
bool eof = pm_parse_stream_read(buffer, stream, stream_fgets);
|
23001
|
+
bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
|
23002
|
+
|
22885
23003
|
pm_parser_init(parser, (const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
|
22886
23004
|
pm_node_t *node = pm_parse(parser);
|
22887
23005
|
|
22888
23006
|
while (!eof && parser->error_list.size > 0 && (parser->lex_modes.index > 0 || pm_parse_stream_unterminated_heredoc_p(parser))) {
|
22889
23007
|
pm_node_destroy(parser, node);
|
22890
|
-
eof = pm_parse_stream_read(buffer, stream, stream_fgets);
|
23008
|
+
eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
|
22891
23009
|
|
22892
23010
|
pm_parser_free(parser);
|
22893
23011
|
pm_parser_init(parser, (const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
|
@@ -22979,13 +23097,13 @@ pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, cons
|
|
22979
23097
|
* given stream into to the given buffer.
|
22980
23098
|
*/
|
22981
23099
|
PRISM_EXPORTED_FUNCTION void
|
22982
|
-
pm_serialize_parse_stream(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, const char *data) {
|
23100
|
+
pm_serialize_parse_stream(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof, const char *data) {
|
22983
23101
|
pm_parser_t parser;
|
22984
23102
|
pm_options_t options = { 0 };
|
22985
23103
|
pm_options_read(&options, data);
|
22986
23104
|
|
22987
23105
|
pm_buffer_t parser_buffer;
|
22988
|
-
pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, stream_fgets, &options);
|
23106
|
+
pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, stream_fgets, stream_feof, &options);
|
22989
23107
|
pm_serialize_header(buffer);
|
22990
23108
|
pm_serialize_content(&parser, node, buffer);
|
22991
23109
|
pm_buffer_append_byte(buffer, '\0');
|