diff --git a/.github/workflows/cruby-bindings.yml b/.github/workflows/cruby-bindings.yml index d635e550f0..918bee4098 100644 --- a/.github/workflows/cruby-bindings.yml +++ b/.github/workflows/cruby-bindings.yml @@ -32,6 +32,7 @@ jobs: with: repository: ruby/ruby path: ruby/ruby + ref: ruby_4_0 fetch-depth: 1 - name: Install libraries run: | diff --git a/config.yml b/config.yml index 5e29d6fa18..2d51ca0496 100644 --- a/config.yml +++ b/config.yml @@ -17,6 +17,8 @@ errors: - ARGUMENT_FORWARDING_UNBOUND - ARGUMENT_NO_FORWARDING_AMPERSAND - ARGUMENT_NO_FORWARDING_ELLIPSES + - ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA + - ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK - ARGUMENT_NO_FORWARDING_STAR - ARGUMENT_NO_FORWARDING_STAR_STAR - ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT diff --git a/snapshots/4.0/leading_logical.txt b/snapshots/4.0/leading_logical.txt index 9e043a88ce..c8ecaa40ba 100644 --- a/snapshots/4.0/leading_logical.txt +++ b/snapshots/4.0/leading_logical.txt @@ -1,10 +1,10 @@ -@ ProgramNode (location: (1,0)-(21,5)) +@ ProgramNode (location: (1,0)-(15,4)) ├── flags: ∅ ├── locals: [] └── statements: - @ StatementsNode (location: (1,0)-(21,5)) + @ StatementsNode (location: (1,0)-(15,4)) ├── flags: ∅ - └── body: (length: 8) + └── body: (length: 4) ├── @ AndNode (location: (1,0)-(3,4)) │ ├── flags: newline │ ├── left: @@ -62,50 +62,22 @@ │ │ ├── flags: static_literal, decimal │ │ └── value: 3 │ └── operator_loc: (11,0)-(11,3) = "and" - ├── @ OrNode (location: (13,0)-(15,4)) - │ ├── flags: newline - │ ├── left: - │ │ @ OrNode (location: (13,0)-(14,4)) - │ │ ├── flags: ∅ - │ │ ├── left: - │ │ │ @ IntegerNode (location: (13,0)-(13,1)) - │ │ │ ├── flags: static_literal, decimal - │ │ │ └── value: 1 - │ │ ├── right: - │ │ │ @ IntegerNode (location: (14,3)-(14,4)) - │ │ │ ├── flags: static_literal, decimal - │ │ │ └── value: 2 - │ │ └── operator_loc: (14,0)-(14,2) = "or" - │ ├── right: - │ │ @ IntegerNode (location: (15,3)-(15,4)) - │ │ ├── flags: static_literal, decimal - │ │ └── value: 3 - │ └── operator_loc: (15,0)-(15,2) = "or" - ├── @ IntegerNode (location: (17,0)-(17,1)) - │ ├── flags: newline, static_literal, decimal - │ └── value: 1 - ├── @ CallNode (location: (18,0)-(18,6)) - │ ├── flags: newline, variable_call, ignore_visibility - │ ├── receiver: ∅ - │ ├── call_operator_loc: ∅ - │ ├── name: :andfoo - │ ├── message_loc: (18,0)-(18,6) = "andfoo" - │ ├── opening_loc: ∅ - │ ├── arguments: ∅ - │ ├── closing_loc: ∅ - │ ├── equal_loc: ∅ - │ └── block: ∅ - ├── @ IntegerNode (location: (20,0)-(20,1)) - │ ├── flags: newline, static_literal, decimal - │ └── value: 2 - └── @ CallNode (location: (21,0)-(21,5)) - ├── flags: newline, variable_call, ignore_visibility - ├── receiver: ∅ - ├── call_operator_loc: ∅ - ├── name: :orfoo - ├── message_loc: (21,0)-(21,5) = "orfoo" - ├── opening_loc: ∅ - ├── arguments: ∅ - ├── closing_loc: ∅ - ├── equal_loc: ∅ - └── block: ∅ + └── @ OrNode (location: (13,0)-(15,4)) + ├── flags: newline + ├── left: + │ @ OrNode (location: (13,0)-(14,4)) + │ ├── flags: ∅ + │ ├── left: + │ │ @ IntegerNode (location: (13,0)-(13,1)) + │ │ ├── flags: static_literal, decimal + │ │ └── value: 1 + │ ├── right: + │ │ @ IntegerNode (location: (14,3)-(14,4)) + │ │ ├── flags: static_literal, decimal + │ │ └── value: 2 + │ └── operator_loc: (14,0)-(14,2) = "or" + ├── right: + │ @ IntegerNode (location: (15,3)-(15,4)) + │ ├── flags: static_literal, decimal + │ └── value: 3 + └── operator_loc: (15,0)-(15,2) = "or" diff --git a/snapshots/and_or_with_suffix.txt b/snapshots/and_or_with_suffix.txt new file mode 100644 index 0000000000..593dee1766 --- /dev/null +++ b/snapshots/and_or_with_suffix.txt @@ -0,0 +1,139 @@ +@ ProgramNode (location: (1,0)-(17,5)) +├── flags: ∅ +├── locals: [] +└── statements: + @ StatementsNode (location: (1,0)-(17,5)) + ├── flags: ∅ + └── body: (length: 12) + ├── @ CallNode (location: (1,0)-(1,3)) + │ ├── flags: newline, variable_call, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (1,0)-(1,3) = "foo" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (2,0)-(2,4)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :and? + │ ├── message_loc: (2,0)-(2,4) = "and?" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (4,0)-(4,3)) + │ ├── flags: newline, variable_call, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (4,0)-(4,3) = "foo" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (5,0)-(5,3)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :or? + │ ├── message_loc: (5,0)-(5,3) = "or?" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (7,0)-(7,3)) + │ ├── flags: newline, variable_call, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (7,0)-(7,3) = "foo" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (8,0)-(8,4)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :and! + │ ├── message_loc: (8,0)-(8,4) = "and!" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (10,0)-(10,3)) + │ ├── flags: newline, variable_call, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (10,0)-(10,3) = "foo" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (11,0)-(11,3)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :or! + │ ├── message_loc: (11,0)-(11,3) = "or!" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (13,0)-(13,3)) + │ ├── flags: newline, variable_call, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (13,0)-(13,3) = "foo" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (14,0)-(14,6)) + │ ├── flags: newline, variable_call, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :andbar + │ ├── message_loc: (14,0)-(14,6) = "andbar" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (16,0)-(16,3)) + │ ├── flags: newline, variable_call, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (16,0)-(16,3) = "foo" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ ├── equal_loc: ∅ + │ └── block: ∅ + └── @ CallNode (location: (17,0)-(17,5)) + ├── flags: newline, variable_call, ignore_visibility + ├── receiver: ∅ + ├── call_operator_loc: ∅ + ├── name: :orbar + ├── message_loc: (17,0)-(17,5) = "orbar" + ├── opening_loc: ∅ + ├── arguments: ∅ + ├── closing_loc: ∅ + ├── equal_loc: ∅ + └── block: ∅ diff --git a/snapshots/case_in_in.txt b/snapshots/case_in_in.txt new file mode 100644 index 0000000000..0fcedb0e89 --- /dev/null +++ b/snapshots/case_in_in.txt @@ -0,0 +1,81 @@ +@ ProgramNode (location: (1,0)-(4,3)) +├── flags: ∅ +├── locals: [:event] +└── statements: + @ StatementsNode (location: (1,0)-(4,3)) + ├── flags: ∅ + └── body: (length: 1) + └── @ CaseMatchNode (location: (1,0)-(4,3)) + ├── flags: newline + ├── predicate: + │ @ CallNode (location: (1,5)-(1,9)) + │ ├── flags: variable_call, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :args + │ ├── message_loc: (1,5)-(1,9) = "args" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── conditions: (length: 1) + │ └── @ InNode (location: (2,0)-(3,25)) + │ ├── flags: ∅ + │ ├── pattern: + │ │ @ ArrayPatternNode (location: (2,3)-(2,10)) + │ │ ├── flags: ∅ + │ │ ├── constant: ∅ + │ │ ├── requireds: (length: 1) + │ │ │ └── @ LocalVariableTargetNode (location: (2,4)-(2,9)) + │ │ │ ├── flags: ∅ + │ │ │ ├── name: :event + │ │ │ └── depth: 0 + │ │ ├── rest: ∅ + │ │ ├── posts: (length: 0) + │ │ ├── opening_loc: (2,3)-(2,4) = "[" + │ │ └── closing_loc: (2,9)-(2,10) = "]" + │ ├── statements: + │ │ @ StatementsNode (location: (3,2)-(3,25)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 1) + │ │ └── @ MatchPredicateNode (location: (3,2)-(3,25)) + │ │ ├── flags: newline + │ │ ├── value: + │ │ │ @ CallNode (location: (3,2)-(3,15)) + │ │ │ ├── flags: ∅ + │ │ │ ├── receiver: + │ │ │ │ @ CallNode (location: (3,2)-(3,9)) + │ │ │ │ ├── flags: variable_call, ignore_visibility + │ │ │ │ ├── receiver: ∅ + │ │ │ │ ├── call_operator_loc: ∅ + │ │ │ │ ├── name: :context + │ │ │ │ ├── message_loc: (3,2)-(3,9) = "context" + │ │ │ │ ├── opening_loc: ∅ + │ │ │ │ ├── arguments: ∅ + │ │ │ │ ├── closing_loc: ∅ + │ │ │ │ ├── equal_loc: ∅ + │ │ │ │ └── block: ∅ + │ │ │ ├── call_operator_loc: (3,9)-(3,10) = "." + │ │ │ ├── name: :event + │ │ │ ├── message_loc: (3,10)-(3,15) = "event" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: ∅ + │ │ │ ├── closing_loc: ∅ + │ │ │ ├── equal_loc: ∅ + │ │ │ └── block: ∅ + │ │ ├── pattern: + │ │ │ @ PinnedVariableNode (location: (3,19)-(3,25)) + │ │ │ ├── flags: ∅ + │ │ │ ├── variable: + │ │ │ │ @ LocalVariableReadNode (location: (3,20)-(3,25)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ ├── name: :event + │ │ │ │ └── depth: 0 + │ │ │ └── operator_loc: (3,19)-(3,20) = "^" + │ │ └── operator_loc: (3,16)-(3,18) = "in" + │ ├── in_loc: (2,0)-(2,2) = "in" + │ └── then_loc: ∅ + ├── else_clause: ∅ + ├── case_keyword_loc: (1,0)-(1,4) = "case" + └── end_keyword_loc: (4,0)-(4,3) = "end" diff --git a/src/prism.c b/src/prism.c index b36a6da204..222bb2dac2 100644 --- a/src/prism.c +++ b/src/prism.c @@ -9979,8 +9979,21 @@ parser_lex(pm_parser_t *parser) { following && ( (peek_at(parser, following) == '&' && peek_at(parser, following + 1) == '&') || (peek_at(parser, following) == '|' && peek_at(parser, following + 1) == '|') || - (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))) || - (peek_at(parser, following) == 'o' && peek_at(parser, following + 1) == 'r' && !char_is_identifier(parser, following + 2, parser->end - (following + 2))) + ( + peek_at(parser, following) == 'a' && + peek_at(parser, following + 1) == 'n' && + peek_at(parser, following + 2) == 'd' && + peek_at(parser, next_content + 3) != '!' && + peek_at(parser, next_content + 3) != '?' && + !char_is_identifier(parser, following + 3, parser->end - (following + 3)) + ) || + ( + peek_at(parser, following) == 'o' && + peek_at(parser, following + 1) == 'r' && + peek_at(parser, next_content + 2) != '!' && + peek_at(parser, next_content + 2) != '?' && + !char_is_identifier(parser, following + 2, parser->end - (following + 2)) + ) ) ) { if (!lexed_comment) parser_lex_ignored_newline(parser); @@ -10051,6 +10064,8 @@ parser_lex(pm_parser_t *parser) { peek_at(parser, next_content) == 'a' && peek_at(parser, next_content + 1) == 'n' && peek_at(parser, next_content + 2) == 'd' && + peek_at(parser, next_content + 3) != '!' && + peek_at(parser, next_content + 3) != '?' && !char_is_identifier(parser, next_content + 3, parser->end - (next_content + 3)) ) { if (!lexed_comment) parser_lex_ignored_newline(parser); @@ -10067,6 +10082,8 @@ parser_lex(pm_parser_t *parser) { if ( peek_at(parser, next_content) == 'o' && peek_at(parser, next_content + 1) == 'r' && + peek_at(parser, next_content + 2) != '!' && + peek_at(parser, next_content + 2) != '?' && !char_is_identifier(parser, next_content + 2, parser->end - (next_content + 2)) ) { if (!lexed_comment) parser_lex_ignored_newline(parser); @@ -13859,6 +13876,7 @@ parse_parameters( bool allows_forwarding_parameters, bool accepts_blocks_in_defaults, bool in_block, + pm_diagnostic_id_t diag_id_forwarding, uint16_t depth ) { pm_do_loop_stack_push(parser, false); @@ -13914,7 +13932,7 @@ parse_parameters( } case PM_TOKEN_UDOT_DOT_DOT: { if (!allows_forwarding_parameters) { - pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES); + pm_parser_err_current(parser, diag_id_forwarding); } bool succeeded = update_parameter_state(parser, &parser->current, &order); @@ -14594,6 +14612,7 @@ parse_block_parameters( false, accepts_blocks_in_defaults, true, + is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK, (uint16_t) (depth + 1) ); if (!is_lambda_literal) { @@ -18836,7 +18855,17 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) { params = NULL; } else { - params = parse_parameters(parser, PM_BINDING_POWER_DEFINED, true, false, true, true, false, (uint16_t) (depth + 1)); + params = parse_parameters( + parser, + PM_BINDING_POWER_DEFINED, + true, + false, + true, + true, + false, + PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES, + (uint16_t) (depth + 1) + ); } lex_state_set(parser, PM_LEX_STATE_BEG); @@ -18861,7 +18890,17 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b lparen = not_provided(parser); rparen = not_provided(parser); - params = parse_parameters(parser, PM_BINDING_POWER_DEFINED, false, false, true, true, false, (uint16_t) (depth + 1)); + params = parse_parameters( + parser, + PM_BINDING_POWER_DEFINED, + false, + false, + true, + true, + false, + PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES, + (uint16_t) (depth + 1) + ); // Reject `def * = 1` and similar. We have to specifically check // for them because they create ambiguity with optional arguments. @@ -21639,12 +21678,6 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc ) { node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right, accepts_command_call, (uint16_t) (depth + 1)); - if (context_terminator(parser->current_context->context, &parser->current)) { - // If this token terminates the current context, then we need to - // stop parsing the expression, as it has become a statement. - return node; - } - switch (PM_NODE_TYPE(node)) { case PM_MULTI_WRITE_NODE: // Multi-write nodes are statements, and cannot be followed by @@ -21757,6 +21790,17 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc break; } } + + if (context_terminator(parser->current_context->context, &parser->current)) { + pm_binding_powers_t next_binding_powers = pm_binding_powers[parser->current.type]; + if ( + !next_binding_powers.binary || + binding_power > next_binding_powers.left || + (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((pm_call_node_t *) node)) + ) { + return node; + } + } } return node; diff --git a/templates/src/diagnostic.c.erb b/templates/src/diagnostic.c.erb index 121dd4b2b6..98f9b922ed 100644 --- a/templates/src/diagnostic.c.erb +++ b/templates/src/diagnostic.c.erb @@ -102,6 +102,8 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = { [PM_ERR_ARGUMENT_FORWARDING_UNBOUND] = { "unexpected `...` in an non-parenthesized call", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND] = { "unexpected `&`; no anonymous block parameter", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES] = { "unexpected ... when the parent method is not forwarding", PM_ERROR_LEVEL_SYNTAX }, + [PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA] = { "unexpected ... in lambda argument", PM_ERROR_LEVEL_SYNTAX }, + [PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK] = { "unexpected ... in block argument", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ARGUMENT_NO_FORWARDING_STAR] = { "unexpected `*`; no anonymous rest parameter", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR] = { "unexpected `**`; no anonymous keyword rest parameter", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT] = { "unexpected `*` splat argument after a `**` keyword splat argument", PM_ERROR_LEVEL_SYNTAX }, diff --git a/test/prism/errors/do_not_allow_forward_arguments_in_blocks.txt b/test/prism/errors/do_not_allow_forward_arguments_in_blocks.txt index df49557617..639dec3af2 100644 --- a/test/prism/errors/do_not_allow_forward_arguments_in_blocks.txt +++ b/test/prism/errors/do_not_allow_forward_arguments_in_blocks.txt @@ -1,3 +1,13 @@ a {|...|} - ^~~ unexpected ... when the parent method is not forwarding + ^~~ unexpected ... in block argument + +def foo(...) + a {|...|} + ^~~ unexpected ... in block argument +end + +def foo + a {|...|} + ^~~ unexpected ... in block argument +end diff --git a/test/prism/errors/do_not_allow_forward_arguments_in_lambda_literals.txt b/test/prism/errors/do_not_allow_forward_arguments_in_lambda_literals.txt index c2405a5c66..03e17683e4 100644 --- a/test/prism/errors/do_not_allow_forward_arguments_in_lambda_literals.txt +++ b/test/prism/errors/do_not_allow_forward_arguments_in_lambda_literals.txt @@ -1,3 +1,13 @@ ->(...) {} - ^~~ unexpected ... when the parent method is not forwarding + ^~~ unexpected ... in lambda argument + +def foo(...) + ->(...) {} + ^~~ unexpected ... in lambda argument +end + +def foo + ->(...) {} + ^~~ unexpected ... in lambda argument +end diff --git a/test/prism/fixtures/4.0/leading_logical.txt b/test/prism/fixtures/4.0/leading_logical.txt index feb5ee245c..ee87e00d4f 100644 --- a/test/prism/fixtures/4.0/leading_logical.txt +++ b/test/prism/fixtures/4.0/leading_logical.txt @@ -14,8 +14,3 @@ and 3 or 2 or 3 -1 -andfoo - -2 -orfoo diff --git a/test/prism/fixtures/and_or_with_suffix.txt b/test/prism/fixtures/and_or_with_suffix.txt new file mode 100644 index 0000000000..59ee4d0b88 --- /dev/null +++ b/test/prism/fixtures/and_or_with_suffix.txt @@ -0,0 +1,17 @@ +foo +and? + +foo +or? + +foo +and! + +foo +or! + +foo +andbar + +foo +orbar diff --git a/test/prism/fixtures/case_in_in.txt b/test/prism/fixtures/case_in_in.txt new file mode 100644 index 0000000000..a5f9e4ec41 --- /dev/null +++ b/test/prism/fixtures/case_in_in.txt @@ -0,0 +1,4 @@ +case args +in [event] + context.event in ^event +end diff --git a/test/prism/lex_test.rb b/test/prism/lex_test.rb index 68e47a0964..d3fdb4277e 100644 --- a/test/prism/lex_test.rb +++ b/test/prism/lex_test.rb @@ -36,6 +36,13 @@ class LexTest < TestCase except << "whitequark/ruby_bug_19281.txt" end + if RUBY_VERSION.start_with?("4.") + except += [ + # https://bugs.ruby-lang.org/issues/21945 + "and_or_with_suffix.txt", + ] + end + # https://bugs.ruby-lang.org/issues/21168#note-5 except << "command_method_call_2.txt" diff --git a/test/prism/ruby/ripper_test.rb b/test/prism/ruby/ripper_test.rb index bbd85585a9..46b0970e68 100644 --- a/test/prism/ruby/ripper_test.rb +++ b/test/prism/ruby/ripper_test.rb @@ -37,6 +37,13 @@ class RipperTest < TestCase ] end + if RUBY_VERSION.start_with?("4.") + incorrect += [ + # https://bugs.ruby-lang.org/issues/21945 + "and_or_with_suffix.txt", + ] + end + # Skip these tests that we haven't implemented yet. omitted = [ "dos_endings.txt",