prism 1.4.0 → 1.5.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 +23 -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 +2 -2
- 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 +24 -19
- 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 +252 -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;
|
@@ -5279,6 +5279,10 @@ pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_
|
|
5279
5279
|
|
5280
5280
|
switch (PM_NODE_TYPE(part)) {
|
5281
5281
|
case PM_STRING_NODE:
|
5282
|
+
// If inner string is not frozen, clear flags for this string
|
5283
|
+
if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
|
5284
|
+
CLEAR_FLAGS(node);
|
5285
|
+
}
|
5282
5286
|
part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
|
5283
5287
|
break;
|
5284
5288
|
case PM_INTERPOLATED_STRING_NODE:
|
@@ -8582,85 +8586,66 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
|
|
8582
8586
|
/* Context manipulations */
|
8583
8587
|
/******************************************************************************/
|
8584
8588
|
|
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
|
-
}
|
8589
|
+
static const uint32_t context_terminators[] = {
|
8590
|
+
[PM_CONTEXT_NONE] = 0,
|
8591
|
+
[PM_CONTEXT_BEGIN] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8592
|
+
[PM_CONTEXT_BEGIN_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8593
|
+
[PM_CONTEXT_BEGIN_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8594
|
+
[PM_CONTEXT_BEGIN_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8595
|
+
[PM_CONTEXT_BLOCK_BRACES] = (1 << PM_TOKEN_BRACE_RIGHT),
|
8596
|
+
[PM_CONTEXT_BLOCK_KEYWORDS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
8597
|
+
[PM_CONTEXT_BLOCK_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8598
|
+
[PM_CONTEXT_BLOCK_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8599
|
+
[PM_CONTEXT_BLOCK_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8600
|
+
[PM_CONTEXT_CASE_WHEN] = (1 << PM_TOKEN_KEYWORD_WHEN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
|
8601
|
+
[PM_CONTEXT_CASE_IN] = (1 << PM_TOKEN_KEYWORD_IN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
|
8602
|
+
[PM_CONTEXT_CLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
8603
|
+
[PM_CONTEXT_CLASS_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8604
|
+
[PM_CONTEXT_CLASS_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8605
|
+
[PM_CONTEXT_CLASS_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] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
8607
|
+
[PM_CONTEXT_DEF_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8608
|
+
[PM_CONTEXT_DEF_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8609
|
+
[PM_CONTEXT_DEF_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8610
|
+
[PM_CONTEXT_DEF_PARAMS] = (1 << PM_TOKEN_EOF),
|
8611
|
+
[PM_CONTEXT_DEFINED] = (1 << PM_TOKEN_EOF),
|
8612
|
+
[PM_CONTEXT_DEFAULT_PARAMS] = (1 << PM_TOKEN_COMMA) | (1 << PM_TOKEN_PARENTHESIS_RIGHT),
|
8613
|
+
[PM_CONTEXT_ELSE] = (1 << PM_TOKEN_KEYWORD_END),
|
8614
|
+
[PM_CONTEXT_ELSIF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
|
8615
|
+
[PM_CONTEXT_EMBEXPR] = (1 << PM_TOKEN_EMBEXPR_END),
|
8616
|
+
[PM_CONTEXT_FOR] = (1 << PM_TOKEN_KEYWORD_END),
|
8617
|
+
[PM_CONTEXT_FOR_INDEX] = (1 << PM_TOKEN_KEYWORD_IN),
|
8618
|
+
[PM_CONTEXT_IF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
|
8619
|
+
[PM_CONTEXT_LAMBDA_BRACES] = (1 << PM_TOKEN_BRACE_RIGHT),
|
8620
|
+
[PM_CONTEXT_LAMBDA_DO_END] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
8621
|
+
[PM_CONTEXT_LAMBDA_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8622
|
+
[PM_CONTEXT_LAMBDA_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8623
|
+
[PM_CONTEXT_LAMBDA_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8624
|
+
[PM_CONTEXT_LOOP_PREDICATE] = (1 << PM_TOKEN_KEYWORD_DO) | (1 << PM_TOKEN_KEYWORD_THEN),
|
8625
|
+
[PM_CONTEXT_MAIN] = (1 << PM_TOKEN_EOF),
|
8626
|
+
[PM_CONTEXT_MODULE] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
8627
|
+
[PM_CONTEXT_MODULE_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8628
|
+
[PM_CONTEXT_MODULE_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8629
|
+
[PM_CONTEXT_MODULE_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8630
|
+
[PM_CONTEXT_MULTI_TARGET] = (1 << PM_TOKEN_EOF),
|
8631
|
+
[PM_CONTEXT_PARENS] = (1 << PM_TOKEN_PARENTHESIS_RIGHT),
|
8632
|
+
[PM_CONTEXT_POSTEXE] = (1 << PM_TOKEN_BRACE_RIGHT),
|
8633
|
+
[PM_CONTEXT_PREDICATE] = (1 << PM_TOKEN_KEYWORD_THEN) | (1 << PM_TOKEN_NEWLINE) | (1 << PM_TOKEN_SEMICOLON),
|
8634
|
+
[PM_CONTEXT_PREEXE] = (1 << PM_TOKEN_BRACE_RIGHT),
|
8635
|
+
[PM_CONTEXT_RESCUE_MODIFIER] = (1 << PM_TOKEN_EOF),
|
8636
|
+
[PM_CONTEXT_SCLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
8637
|
+
[PM_CONTEXT_SCLASS_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
8638
|
+
[PM_CONTEXT_SCLASS_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
8639
|
+
[PM_CONTEXT_SCLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8640
|
+
[PM_CONTEXT_TERNARY] = (1 << PM_TOKEN_EOF),
|
8641
|
+
[PM_CONTEXT_UNLESS] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
8642
|
+
[PM_CONTEXT_UNTIL] = (1 << PM_TOKEN_KEYWORD_END),
|
8643
|
+
[PM_CONTEXT_WHILE] = (1 << PM_TOKEN_KEYWORD_END),
|
8644
|
+
};
|
8662
8645
|
|
8663
|
-
|
8646
|
+
static inline bool
|
8647
|
+
context_terminator(pm_context_t context, pm_token_t *token) {
|
8648
|
+
return token->type < 32 && (context_terminators[context] & (1 << token->type));
|
8664
8649
|
}
|
8665
8650
|
|
8666
8651
|
/**
|
@@ -9109,7 +9094,7 @@ lex_global_variable(pm_parser_t *parser) {
|
|
9109
9094
|
} while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
|
9110
9095
|
|
9111
9096
|
// $0 isn't allowed to be followed by anything.
|
9112
|
-
pm_diagnostic_id_t diag_id = parser->version
|
9097
|
+
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
9098
|
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, diag_id);
|
9114
9099
|
}
|
9115
9100
|
|
@@ -9146,7 +9131,7 @@ lex_global_variable(pm_parser_t *parser) {
|
|
9146
9131
|
} else {
|
9147
9132
|
// If we get here, then we have a $ followed by something that
|
9148
9133
|
// isn't recognized as a global variable.
|
9149
|
-
pm_diagnostic_id_t diag_id = parser->version
|
9134
|
+
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
9135
|
const uint8_t *end = parser->current.end + parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
|
9151
9136
|
PM_PARSER_ERR_FORMAT(parser, parser->current.start, end, diag_id, (int) (end - parser->current.start), (const char *) parser->current.start);
|
9152
9137
|
}
|
@@ -10173,7 +10158,7 @@ lex_at_variable(pm_parser_t *parser) {
|
|
10173
10158
|
}
|
10174
10159
|
} else if (parser->current.end < end && pm_char_is_decimal_digit(*parser->current.end)) {
|
10175
10160
|
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
|
10161
|
+
if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) {
|
10177
10162
|
diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
|
10178
10163
|
}
|
10179
10164
|
|
@@ -10849,14 +10834,37 @@ parser_lex(pm_parser_t *parser) {
|
|
10849
10834
|
following = next_newline(following, parser->end - following);
|
10850
10835
|
}
|
10851
10836
|
|
10852
|
-
// If the lex state was ignored,
|
10853
|
-
//
|
10837
|
+
// If the lex state was ignored, we will lex the
|
10838
|
+
// ignored newline.
|
10839
|
+
if (lex_state_ignored_p(parser)) {
|
10840
|
+
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10841
|
+
lexed_comment = false;
|
10842
|
+
goto lex_next_token;
|
10843
|
+
}
|
10844
|
+
|
10845
|
+
// If we hit a '.' or a '&.' we will lex the ignored
|
10846
|
+
// newline.
|
10847
|
+
if (following && (
|
10848
|
+
(peek_at(parser, following) == '.') ||
|
10849
|
+
(peek_at(parser, following) == '&' && peek_at(parser, following + 1) == '.')
|
10850
|
+
)) {
|
10851
|
+
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10852
|
+
lexed_comment = false;
|
10853
|
+
goto lex_next_token;
|
10854
|
+
}
|
10855
|
+
|
10856
|
+
|
10857
|
+
// If we are parsing as CRuby 3.5 or later and we
|
10858
|
+
// hit a '&&' or a '||' then we will lex the ignored
|
10859
|
+
// newline.
|
10854
10860
|
if (
|
10855
|
-
|
10856
|
-
|
10857
|
-
(peek_at(parser, following) == '
|
10858
|
-
(peek_at(parser, following) == '
|
10859
|
-
|
10861
|
+
(parser->version >= PM_OPTIONS_VERSION_CRUBY_3_5) &&
|
10862
|
+
following && (
|
10863
|
+
(peek_at(parser, following) == '&' && peek_at(parser, following + 1) == '&') ||
|
10864
|
+
(peek_at(parser, following) == '|' && peek_at(parser, following + 1) == '|') ||
|
10865
|
+
(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))) ||
|
10866
|
+
(peek_at(parser, following) == 'o' && peek_at(parser, following + 1) == 'r' && !char_is_identifier(parser, following + 2, parser->end - (following + 2)))
|
10867
|
+
)
|
10860
10868
|
) {
|
10861
10869
|
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10862
10870
|
lexed_comment = false;
|
@@ -10896,6 +10904,63 @@ parser_lex(pm_parser_t *parser) {
|
|
10896
10904
|
parser->next_start = NULL;
|
10897
10905
|
LEX(PM_TOKEN_AMPERSAND_DOT);
|
10898
10906
|
}
|
10907
|
+
|
10908
|
+
if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_5) {
|
10909
|
+
// If we hit an && then we are in a logical chain
|
10910
|
+
// and we need to return the logical operator.
|
10911
|
+
if (peek_at(parser, next_content) == '&' && peek_at(parser, next_content + 1) == '&') {
|
10912
|
+
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10913
|
+
lex_state_set(parser, PM_LEX_STATE_BEG);
|
10914
|
+
parser->current.start = next_content;
|
10915
|
+
parser->current.end = next_content + 2;
|
10916
|
+
parser->next_start = NULL;
|
10917
|
+
LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
|
10918
|
+
}
|
10919
|
+
|
10920
|
+
// If we hit a || then we are in a logical chain and
|
10921
|
+
// we need to return the logical operator.
|
10922
|
+
if (peek_at(parser, next_content) == '|' && peek_at(parser, next_content + 1) == '|') {
|
10923
|
+
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10924
|
+
lex_state_set(parser, PM_LEX_STATE_BEG);
|
10925
|
+
parser->current.start = next_content;
|
10926
|
+
parser->current.end = next_content + 2;
|
10927
|
+
parser->next_start = NULL;
|
10928
|
+
LEX(PM_TOKEN_PIPE_PIPE);
|
10929
|
+
}
|
10930
|
+
|
10931
|
+
// If we hit an 'and' then we are in a logical chain
|
10932
|
+
// and we need to return the logical operator.
|
10933
|
+
if (
|
10934
|
+
peek_at(parser, next_content) == 'a' &&
|
10935
|
+
peek_at(parser, next_content + 1) == 'n' &&
|
10936
|
+
peek_at(parser, next_content + 2) == 'd' &&
|
10937
|
+
!char_is_identifier(parser, next_content + 3, parser->end - (next_content + 3))
|
10938
|
+
) {
|
10939
|
+
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10940
|
+
lex_state_set(parser, PM_LEX_STATE_BEG);
|
10941
|
+
parser->current.start = next_content;
|
10942
|
+
parser->current.end = next_content + 3;
|
10943
|
+
parser->next_start = NULL;
|
10944
|
+
parser->command_start = true;
|
10945
|
+
LEX(PM_TOKEN_KEYWORD_AND);
|
10946
|
+
}
|
10947
|
+
|
10948
|
+
// If we hit a 'or' then we are in a logical chain
|
10949
|
+
// and we need to return the logical operator.
|
10950
|
+
if (
|
10951
|
+
peek_at(parser, next_content) == 'o' &&
|
10952
|
+
peek_at(parser, next_content + 1) == 'r' &&
|
10953
|
+
!char_is_identifier(parser, next_content + 2, parser->end - (next_content + 2))
|
10954
|
+
) {
|
10955
|
+
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
10956
|
+
lex_state_set(parser, PM_LEX_STATE_BEG);
|
10957
|
+
parser->current.start = next_content;
|
10958
|
+
parser->current.end = next_content + 2;
|
10959
|
+
parser->next_start = NULL;
|
10960
|
+
parser->command_start = true;
|
10961
|
+
LEX(PM_TOKEN_KEYWORD_OR);
|
10962
|
+
}
|
10963
|
+
}
|
10899
10964
|
}
|
10900
10965
|
|
10901
10966
|
// At this point we know this is a regular newline, and we can set the
|
@@ -13142,14 +13207,6 @@ match8(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2,
|
|
13142
13207
|
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
13208
|
}
|
13144
13209
|
|
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
13210
|
/**
|
13154
13211
|
* If the current token is of the specified type, lex forward by one token and
|
13155
13212
|
* return true. Otherwise, return false. For example:
|
@@ -14671,7 +14728,7 @@ parse_parameters(
|
|
14671
14728
|
parser_lex(parser);
|
14672
14729
|
|
14673
14730
|
pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &name);
|
14674
|
-
uint32_t reads = parser->version
|
14731
|
+
uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
|
14675
14732
|
|
14676
14733
|
if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser, true);
|
14677
14734
|
pm_node_t *value = parse_value_expression(parser, binding_power, false, false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
|
@@ -14687,7 +14744,7 @@ parse_parameters(
|
|
14687
14744
|
// If the value of the parameter increased the number of
|
14688
14745
|
// reads of that parameter, then we need to warn that we
|
14689
14746
|
// have a circular definition.
|
14690
|
-
if ((parser->version
|
14747
|
+
if ((parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
|
14691
14748
|
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
|
14692
14749
|
}
|
14693
14750
|
|
@@ -14772,13 +14829,13 @@ parse_parameters(
|
|
14772
14829
|
|
14773
14830
|
if (token_begins_expression_p(parser->current.type)) {
|
14774
14831
|
pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &local);
|
14775
|
-
uint32_t reads = parser->version
|
14832
|
+
uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
|
14776
14833
|
|
14777
14834
|
if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser, true);
|
14778
14835
|
pm_node_t *value = parse_value_expression(parser, binding_power, false, false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
|
14779
14836
|
if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
|
14780
14837
|
|
14781
|
-
if (parser->version
|
14838
|
+
if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
|
14782
14839
|
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
|
14783
14840
|
}
|
14784
14841
|
|
@@ -16482,7 +16539,7 @@ parse_variable(pm_parser_t *parser) {
|
|
16482
16539
|
pm_node_list_append(¤t_scope->implicit_parameters, node);
|
16483
16540
|
|
16484
16541
|
return node;
|
16485
|
-
} else if ((parser->version
|
16542
|
+
} else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.start, parser->previous.end)) {
|
16486
16543
|
pm_node_t *node = (pm_node_t *) pm_it_local_variable_read_node_create(parser, &parser->previous);
|
16487
16544
|
pm_node_list_append(¤t_scope->implicit_parameters, node);
|
16488
16545
|
|
@@ -17412,6 +17469,14 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
|
|
17412
17469
|
// If we found a label, we need to immediately return to the caller.
|
17413
17470
|
if (pm_symbol_node_label_p(node)) return node;
|
17414
17471
|
|
17472
|
+
// Call nodes (arithmetic operations) are not allowed in patterns
|
17473
|
+
if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
|
17474
|
+
pm_parser_err_node(parser, node, diag_id);
|
17475
|
+
pm_missing_node_t *missing_node = pm_missing_node_create(parser, node->location.start, node->location.end);
|
17476
|
+
pm_node_destroy(parser, node);
|
17477
|
+
return (pm_node_t *) missing_node;
|
17478
|
+
}
|
17479
|
+
|
17415
17480
|
// Now that we have a primitive, we need to check if it's part of a range.
|
17416
17481
|
if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
|
17417
17482
|
pm_token_t operator = parser->previous;
|
@@ -17694,7 +17759,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
|
|
17694
17759
|
// Gather up all of the patterns into the list.
|
17695
17760
|
while (accept1(parser, PM_TOKEN_COMMA)) {
|
17696
17761
|
// Break early here in case we have a trailing comma.
|
17697
|
-
if (
|
17762
|
+
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
17763
|
node = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
|
17699
17764
|
pm_node_list_append(&nodes, node);
|
17700
17765
|
trailing_rest = true;
|
@@ -18585,17 +18650,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
18585
18650
|
call->closing_loc = arguments.closing_loc;
|
18586
18651
|
call->block = arguments.block;
|
18587
18652
|
|
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;
|
18653
|
+
const uint8_t *end = pm_arguments_end(&arguments);
|
18654
|
+
if (!end) {
|
18655
|
+
end = call->message_loc.end;
|
18598
18656
|
}
|
18657
|
+
call->base.location.end = end;
|
18599
18658
|
}
|
18600
18659
|
} else {
|
18601
18660
|
// Otherwise, we know the identifier is in the local table. This
|
@@ -19123,7 +19182,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
19123
19182
|
pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].left;
|
19124
19183
|
|
19125
19184
|
if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
|
19185
|
+
pm_token_t next = parser->current;
|
19126
19186
|
parse_arguments(parser, &arguments, false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
|
19187
|
+
|
19188
|
+
// Reject `foo && return bar`.
|
19189
|
+
if (!accepts_command_call && arguments.arguments != NULL) {
|
19190
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(next.type));
|
19191
|
+
}
|
19127
19192
|
}
|
19128
19193
|
}
|
19129
19194
|
|
@@ -19520,7 +19585,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
19520
19585
|
pm_do_loop_stack_push(parser, false);
|
19521
19586
|
statements = (pm_node_t *) pm_statements_node_create(parser);
|
19522
19587
|
|
19523
|
-
|
19588
|
+
bool allow_command_call;
|
19589
|
+
if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_5) {
|
19590
|
+
allow_command_call = accepts_command_call;
|
19591
|
+
} else {
|
19592
|
+
// Allow `def foo = puts "Hello"` but not `private def foo = puts "Hello"`
|
19593
|
+
allow_command_call = binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION;
|
19594
|
+
}
|
19595
|
+
|
19596
|
+
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
19597
|
|
19525
19598
|
if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
|
19526
19599
|
context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
|
@@ -19607,18 +19680,27 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
19607
19680
|
pm_token_t lparen;
|
19608
19681
|
pm_token_t rparen;
|
19609
19682
|
pm_node_t *expression;
|
19683
|
+
|
19610
19684
|
context_push(parser, PM_CONTEXT_DEFINED);
|
19685
|
+
bool newline = accept1(parser, PM_TOKEN_NEWLINE);
|
19611
19686
|
|
19612
19687
|
if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
|
19613
19688
|
lparen = parser->previous;
|
19614
|
-
expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
|
19615
19689
|
|
19616
|
-
if (parser
|
19690
|
+
if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
|
19691
|
+
expression = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0);
|
19692
|
+
lparen = not_provided(parser);
|
19617
19693
|
rparen = not_provided(parser);
|
19618
19694
|
} else {
|
19619
|
-
|
19620
|
-
|
19621
|
-
|
19695
|
+
expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
|
19696
|
+
|
19697
|
+
if (parser->recovering) {
|
19698
|
+
rparen = not_provided(parser);
|
19699
|
+
} else {
|
19700
|
+
accept1(parser, PM_TOKEN_NEWLINE);
|
19701
|
+
expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
|
19702
|
+
rparen = parser->previous;
|
19703
|
+
}
|
19622
19704
|
}
|
19623
19705
|
} else {
|
19624
19706
|
lparen = not_provided(parser);
|
@@ -19766,6 +19848,20 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
19766
19848
|
pm_arguments_t arguments = { 0 };
|
19767
19849
|
pm_node_t *receiver = NULL;
|
19768
19850
|
|
19851
|
+
// If we do not accept a command call, then we also do not accept a
|
19852
|
+
// not without parentheses. In this case we need to reject this
|
19853
|
+
// syntax.
|
19854
|
+
if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
|
19855
|
+
if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
|
19856
|
+
pm_parser_err(parser, parser->previous.end, parser->previous.end + 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
|
19857
|
+
} else {
|
19858
|
+
accept1(parser, PM_TOKEN_NEWLINE);
|
19859
|
+
pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
|
19860
|
+
}
|
19861
|
+
|
19862
|
+
return (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
|
19863
|
+
}
|
19864
|
+
|
19769
19865
|
accept1(parser, PM_TOKEN_NEWLINE);
|
19770
19866
|
|
19771
19867
|
if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
|
@@ -21167,6 +21263,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
|
|
21167
21263
|
}
|
21168
21264
|
PRISM_FALLTHROUGH
|
21169
21265
|
case PM_CASE_WRITABLE: {
|
21266
|
+
// When we have `it = value`, we need to add `it` as a local
|
21267
|
+
// variable before parsing the value, in case the value
|
21268
|
+
// references the variable.
|
21269
|
+
if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
|
21270
|
+
pm_parser_local_add_location(parser, node->location.start, node->location.end, 0);
|
21271
|
+
}
|
21272
|
+
|
21170
21273
|
parser_lex(parser);
|
21171
21274
|
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
21275
|
|
@@ -22160,6 +22263,12 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
|
|
22160
22263
|
) {
|
22161
22264
|
node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right, accepts_command_call, (uint16_t) (depth + 1));
|
22162
22265
|
|
22266
|
+
if (context_terminator(parser->current_context->context, &parser->current)) {
|
22267
|
+
// If this token terminates the current context, then we need to
|
22268
|
+
// stop parsing the expression, as it has become a statement.
|
22269
|
+
return node;
|
22270
|
+
}
|
22271
|
+
|
22163
22272
|
switch (PM_NODE_TYPE(node)) {
|
22164
22273
|
case PM_MULTI_WRITE_NODE:
|
22165
22274
|
// Multi-write nodes are statements, and cannot be followed by
|
@@ -22614,6 +22723,12 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
|
|
22614
22723
|
}
|
22615
22724
|
}
|
22616
22725
|
|
22726
|
+
// Now that we have established the user-provided options, check if
|
22727
|
+
// a version was given and parse as the latest version otherwise.
|
22728
|
+
if (parser->version == PM_OPTIONS_VERSION_UNSET) {
|
22729
|
+
parser->version = PM_OPTIONS_VERSION_LATEST;
|
22730
|
+
}
|
22731
|
+
|
22617
22732
|
pm_accepts_block_stack_push(parser, true);
|
22618
22733
|
|
22619
22734
|
// Skip past the UTF-8 BOM if it exists.
|
@@ -22667,7 +22782,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
|
|
22667
22782
|
}
|
22668
22783
|
|
22669
22784
|
search_shebang = false;
|
22670
|
-
} else if (options->main_script && !parser->parsing_eval) {
|
22785
|
+
} else if (options != NULL && options->main_script && !parser->parsing_eval) {
|
22671
22786
|
search_shebang = true;
|
22672
22787
|
}
|
22673
22788
|
}
|
@@ -22807,7 +22922,7 @@ pm_parse(pm_parser_t *parser) {
|
|
22807
22922
|
* otherwise return true.
|
22808
22923
|
*/
|
22809
22924
|
static bool
|
22810
|
-
pm_parse_stream_read(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets) {
|
22925
|
+
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
22926
|
#define LINE_SIZE 4096
|
22812
22927
|
char line[LINE_SIZE];
|
22813
22928
|
|
@@ -22843,6 +22958,12 @@ pm_parse_stream_read(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t
|
|
22843
22958
|
if (strncmp(line, "__END__\r\n", 9) == 0) return false;
|
22844
22959
|
break;
|
22845
22960
|
}
|
22961
|
+
|
22962
|
+
// All data should be read via gets. If the string returned by gets
|
22963
|
+
// _doesn't_ end with a newline, then we assume we hit EOF condition.
|
22964
|
+
if (stream_feof(stream)) {
|
22965
|
+
break;
|
22966
|
+
}
|
22846
22967
|
}
|
22847
22968
|
|
22848
22969
|
return true;
|
@@ -22878,16 +22999,17 @@ pm_parse_stream_unterminated_heredoc_p(pm_parser_t *parser) {
|
|
22878
22999
|
* can stream stdin in to Ruby so we need to support a streaming API.
|
22879
23000
|
*/
|
22880
23001
|
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) {
|
23002
|
+
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
23003
|
pm_buffer_init(buffer);
|
22883
23004
|
|
22884
|
-
bool eof = pm_parse_stream_read(buffer, stream, stream_fgets);
|
23005
|
+
bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
|
23006
|
+
|
22885
23007
|
pm_parser_init(parser, (const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
|
22886
23008
|
pm_node_t *node = pm_parse(parser);
|
22887
23009
|
|
22888
23010
|
while (!eof && parser->error_list.size > 0 && (parser->lex_modes.index > 0 || pm_parse_stream_unterminated_heredoc_p(parser))) {
|
22889
23011
|
pm_node_destroy(parser, node);
|
22890
|
-
eof = pm_parse_stream_read(buffer, stream, stream_fgets);
|
23012
|
+
eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
|
22891
23013
|
|
22892
23014
|
pm_parser_free(parser);
|
22893
23015
|
pm_parser_init(parser, (const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
|
@@ -22979,13 +23101,13 @@ pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, cons
|
|
22979
23101
|
* given stream into to the given buffer.
|
22980
23102
|
*/
|
22981
23103
|
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) {
|
23104
|
+
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
23105
|
pm_parser_t parser;
|
22984
23106
|
pm_options_t options = { 0 };
|
22985
23107
|
pm_options_read(&options, data);
|
22986
23108
|
|
22987
23109
|
pm_buffer_t parser_buffer;
|
22988
|
-
pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, stream_fgets, &options);
|
23110
|
+
pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, stream_fgets, stream_feof, &options);
|
22989
23111
|
pm_serialize_header(buffer);
|
22990
23112
|
pm_serialize_content(&parser, node, buffer);
|
22991
23113
|
pm_buffer_append_byte(buffer, '\0');
|