From 5191b1aa6869795ef12b52a7637e343f00b11fc5 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Fri, 17 Oct 2025 16:19:56 +0200 Subject: [PATCH] Make error and snapshot tests multi-version aware This one has been on my mind for a while now. Currently, there are only tests against the latest syntax version. This changes the snapshot structure as follows: * Snapshots at their current location are tested against all syntax versions * Snapshots inside a version folder like "3.3" are tested against all versions starting from that version * Snapshots inside a version folder like "3.3-4.2" are tested against all versions in the given range. This makes sure that as new syntax is added, older versions still work as expected. I also added a few tests for now valid syntax that should be invalid in older versions (and the other way around as well) These tests run really fast. So even though it does 3x the work for these, I am still able to run the whole test suite in just 11 seconds. --- .../block_args_in_array_assignment.txt | 50 ++ snapshots/3.3-3.3/it.txt | 58 +++ snapshots/3.3-3.3/it_indirect_writes.txt | 455 ++++++++++++++++++ snapshots/3.3-3.3/it_read_and_assignment.txt | 81 ++++ .../3.3-3.3/it_with_ordinary_parameter.txt | 43 ++ .../keyword_args_in_array_assignment.txt | 56 +++ snapshots/3.3-3.3/return_in_sclass.txt | 25 + snapshots/3.4/circular_parameters.txt | 167 +++++++ snapshots/{ => 3.4}/it.txt | 0 snapshots/3.4/it_assignment.txt | 58 +++ snapshots/{ => 3.4}/it_indirect_writes.txt | 0 .../{ => 3.4}/it_read_and_assignment.txt | 0 .../endless_methods_command_call.txt | 0 snapshots/{ => 3.5}/leading_logical.txt | 0 src/prism.c | 2 +- .../errors/3.3-3.3/circular_parameters.txt | 12 + test/prism/errors/3.3-3.4/leading_logical.txt | 34 ++ .../errors/3.3-3.4/private_endless_method.txt | 3 + .../block_args_in_array_assignment.txt | 0 .../dont_allow_return_inside_sclass_body.txt | 0 .../{ => 3.4}/it_with_ordinary_parameter.txt | 0 .../keyword_args_in_array_assignment.txt | 0 test/prism/errors_test.rb | 65 +-- .../block_args_in_array_assignment.txt | 1 + test/prism/fixtures/{ => 3.3-3.3}/it.txt | 0 .../{ => 3.3-3.3}/it_indirect_writes.txt | 0 .../{ => 3.3-3.3}/it_read_and_assignment.txt | 0 .../3.3-3.3/it_with_ordinary_parameter.txt | 1 + .../keyword_args_in_array_assignment.txt | 1 + .../fixtures/3.3-3.3/return_in_sclass.txt | 1 + .../fixtures/3.4/circular_parameters.txt | 4 + test/prism/fixtures/3.4/it.txt | 5 + .../prism/fixtures/3.4/it_indirect_writes.txt | 23 + .../fixtures/3.4/it_read_and_assignment.txt | 1 + .../endless_methods_command_call.txt | 0 .../fixtures/{ => 3.5}/leading_logical.txt | 0 test/prism/fixtures_test.rb | 8 +- test/prism/lex_test.rb | 14 +- test/prism/locals_test.rb | 4 +- test/prism/ruby/parser_test.rb | 13 +- test/prism/ruby/ripper_test.rb | 12 +- test/prism/ruby/ruby_parser_test.rb | 12 +- test/prism/snapshots_test.rb | 18 +- test/prism/snippets_test.rb | 12 +- test/prism/test_helper.rb | 47 +- 45 files changed, 1196 insertions(+), 90 deletions(-) create mode 100644 snapshots/3.3-3.3/block_args_in_array_assignment.txt create mode 100644 snapshots/3.3-3.3/it.txt create mode 100644 snapshots/3.3-3.3/it_indirect_writes.txt create mode 100644 snapshots/3.3-3.3/it_read_and_assignment.txt create mode 100644 snapshots/3.3-3.3/it_with_ordinary_parameter.txt create mode 100644 snapshots/3.3-3.3/keyword_args_in_array_assignment.txt create mode 100644 snapshots/3.3-3.3/return_in_sclass.txt create mode 100644 snapshots/3.4/circular_parameters.txt rename snapshots/{ => 3.4}/it.txt (100%) create mode 100644 snapshots/3.4/it_assignment.txt rename snapshots/{ => 3.4}/it_indirect_writes.txt (100%) rename snapshots/{ => 3.4}/it_read_and_assignment.txt (100%) rename snapshots/{ => 3.5}/endless_methods_command_call.txt (100%) rename snapshots/{ => 3.5}/leading_logical.txt (100%) create mode 100644 test/prism/errors/3.3-3.3/circular_parameters.txt create mode 100644 test/prism/errors/3.3-3.4/leading_logical.txt create mode 100644 test/prism/errors/3.3-3.4/private_endless_method.txt rename test/prism/errors/{ => 3.4}/block_args_in_array_assignment.txt (100%) rename test/prism/errors/{ => 3.4}/dont_allow_return_inside_sclass_body.txt (100%) rename test/prism/errors/{ => 3.4}/it_with_ordinary_parameter.txt (100%) rename test/prism/errors/{ => 3.4}/keyword_args_in_array_assignment.txt (100%) create mode 100644 test/prism/fixtures/3.3-3.3/block_args_in_array_assignment.txt rename test/prism/fixtures/{ => 3.3-3.3}/it.txt (100%) rename test/prism/fixtures/{ => 3.3-3.3}/it_indirect_writes.txt (100%) rename test/prism/fixtures/{ => 3.3-3.3}/it_read_and_assignment.txt (100%) create mode 100644 test/prism/fixtures/3.3-3.3/it_with_ordinary_parameter.txt create mode 100644 test/prism/fixtures/3.3-3.3/keyword_args_in_array_assignment.txt create mode 100644 test/prism/fixtures/3.3-3.3/return_in_sclass.txt create mode 100644 test/prism/fixtures/3.4/circular_parameters.txt create mode 100644 test/prism/fixtures/3.4/it.txt create mode 100644 test/prism/fixtures/3.4/it_indirect_writes.txt create mode 100644 test/prism/fixtures/3.4/it_read_and_assignment.txt rename test/prism/fixtures/{ => 3.5}/endless_methods_command_call.txt (100%) rename test/prism/fixtures/{ => 3.5}/leading_logical.txt (100%) diff --git a/snapshots/3.3-3.3/block_args_in_array_assignment.txt b/snapshots/3.3-3.3/block_args_in_array_assignment.txt new file mode 100644 index 0000000000..03327a51f6 --- /dev/null +++ b/snapshots/3.3-3.3/block_args_in_array_assignment.txt @@ -0,0 +1,50 @@ +@ ProgramNode (location: (1,0)-(1,21)) +├── flags: ∅ +├── locals: [] +└── statements: + @ StatementsNode (location: (1,0)-(1,21)) + ├── flags: ∅ + └── body: (length: 1) + └── @ CallNode (location: (1,0)-(1,21)) + ├── flags: newline, attribute_write + ├── receiver: + │ @ CallNode (location: (1,0)-(1,6)) + │ ├── flags: variable_call, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :matrix + │ ├── message_loc: (1,0)-(1,6) = "matrix" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: ∅ + ├── call_operator_loc: ∅ + ├── name: :[]= + ├── message_loc: (1,6)-(1,17) = "[5, &block]" + ├── opening_loc: (1,6)-(1,7) = "[" + ├── arguments: + │ @ ArgumentsNode (location: (1,7)-(1,21)) + │ ├── flags: ∅ + │ └── arguments: (length: 2) + │ ├── @ IntegerNode (location: (1,7)-(1,8)) + │ │ ├── flags: static_literal, decimal + │ │ └── value: 5 + │ └── @ IntegerNode (location: (1,20)-(1,21)) + │ ├── flags: static_literal, decimal + │ └── value: 8 + ├── closing_loc: (1,16)-(1,17) = "]" + └── block: + @ BlockArgumentNode (location: (1,10)-(1,16)) + ├── flags: ∅ + ├── expression: + │ @ CallNode (location: (1,11)-(1,16)) + │ ├── flags: variable_call, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :block + │ ├── message_loc: (1,11)-(1,16) = "block" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: ∅ + └── operator_loc: (1,10)-(1,11) = "&" diff --git a/snapshots/3.3-3.3/it.txt b/snapshots/3.3-3.3/it.txt new file mode 100644 index 0000000000..a8a8d521c0 --- /dev/null +++ b/snapshots/3.3-3.3/it.txt @@ -0,0 +1,58 @@ +@ ProgramNode (location: (1,0)-(5,9)) +├── flags: ∅ +├── locals: [] +└── statements: + @ StatementsNode (location: (1,0)-(5,9)) + ├── flags: ∅ + └── body: (length: 2) + ├── @ CallNode (location: (1,0)-(3,3)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :x + │ ├── message_loc: (1,0)-(1,1) = "x" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: + │ @ BlockNode (location: (1,2)-(3,3)) + │ ├── flags: ∅ + │ ├── locals: [] + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (2,2)-(2,4)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 1) + │ │ └── @ CallNode (location: (2,2)-(2,4)) + │ │ ├── flags: newline, variable_call, ignore_visibility + │ │ ├── receiver: ∅ + │ │ ├── call_operator_loc: ∅ + │ │ ├── name: :it + │ │ ├── message_loc: (2,2)-(2,4) = "it" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: ∅ + │ │ ├── closing_loc: ∅ + │ │ └── block: ∅ + │ ├── opening_loc: (1,2)-(1,4) = "do" + │ └── closing_loc: (3,0)-(3,3) = "end" + └── @ LambdaNode (location: (5,0)-(5,9)) + ├── flags: newline + ├── locals: [] + ├── operator_loc: (5,0)-(5,2) = "->" + ├── opening_loc: (5,3)-(5,4) = "{" + ├── closing_loc: (5,8)-(5,9) = "}" + ├── parameters: ∅ + └── body: + @ StatementsNode (location: (5,5)-(5,7)) + ├── flags: ∅ + └── body: (length: 1) + └── @ CallNode (location: (5,5)-(5,7)) + ├── flags: newline, variable_call, ignore_visibility + ├── receiver: ∅ + ├── call_operator_loc: ∅ + ├── name: :it + ├── message_loc: (5,5)-(5,7) = "it" + ├── opening_loc: ∅ + ├── arguments: ∅ + ├── closing_loc: ∅ + └── block: ∅ diff --git a/snapshots/3.3-3.3/it_indirect_writes.txt b/snapshots/3.3-3.3/it_indirect_writes.txt new file mode 100644 index 0000000000..918eca9a37 --- /dev/null +++ b/snapshots/3.3-3.3/it_indirect_writes.txt @@ -0,0 +1,455 @@ +@ ProgramNode (location: (1,0)-(23,24)) +├── flags: ∅ +├── locals: [] +└── statements: + @ StatementsNode (location: (1,0)-(23,24)) + ├── flags: ∅ + └── body: (length: 12) + ├── @ CallNode (location: (1,0)-(1,15)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :tap + │ ├── message_loc: (1,0)-(1,3) = "tap" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: + │ @ BlockNode (location: (1,4)-(1,15)) + │ ├── flags: ∅ + │ ├── locals: [:it] + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (1,6)-(1,13)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 1) + │ │ └── @ LocalVariableOperatorWriteNode (location: (1,6)-(1,13)) + │ │ ├── flags: newline + │ │ ├── name_loc: (1,6)-(1,8) = "it" + │ │ ├── binary_operator_loc: (1,9)-(1,11) = "+=" + │ │ ├── value: + │ │ │ @ IntegerNode (location: (1,12)-(1,13)) + │ │ │ ├── flags: static_literal, decimal + │ │ │ └── value: 1 + │ │ ├── name: :it + │ │ ├── binary_operator: :+ + │ │ └── depth: 0 + │ ├── opening_loc: (1,4)-(1,5) = "{" + │ └── closing_loc: (1,14)-(1,15) = "}" + ├── @ CallNode (location: (3,0)-(3,16)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :tap + │ ├── message_loc: (3,0)-(3,3) = "tap" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: + │ @ BlockNode (location: (3,4)-(3,16)) + │ ├── flags: ∅ + │ ├── locals: [:it] + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (3,6)-(3,14)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 1) + │ │ └── @ LocalVariableOrWriteNode (location: (3,6)-(3,14)) + │ │ ├── flags: newline + │ │ ├── name_loc: (3,6)-(3,8) = "it" + │ │ ├── operator_loc: (3,9)-(3,12) = "||=" + │ │ ├── value: + │ │ │ @ IntegerNode (location: (3,13)-(3,14)) + │ │ │ ├── flags: static_literal, decimal + │ │ │ └── value: 1 + │ │ ├── name: :it + │ │ └── depth: 0 + │ ├── opening_loc: (3,4)-(3,5) = "{" + │ └── closing_loc: (3,15)-(3,16) = "}" + ├── @ CallNode (location: (5,0)-(5,16)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :tap + │ ├── message_loc: (5,0)-(5,3) = "tap" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: + │ @ BlockNode (location: (5,4)-(5,16)) + │ ├── flags: ∅ + │ ├── locals: [:it] + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (5,6)-(5,14)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 1) + │ │ └── @ LocalVariableAndWriteNode (location: (5,6)-(5,14)) + │ │ ├── flags: newline + │ │ ├── name_loc: (5,6)-(5,8) = "it" + │ │ ├── operator_loc: (5,9)-(5,12) = "&&=" + │ │ ├── value: + │ │ │ @ IntegerNode (location: (5,13)-(5,14)) + │ │ │ ├── flags: static_literal, decimal + │ │ │ └── value: 1 + │ │ ├── name: :it + │ │ └── depth: 0 + │ ├── opening_loc: (5,4)-(5,5) = "{" + │ └── closing_loc: (5,15)-(5,16) = "}" + ├── @ CallNode (location: (7,0)-(7,19)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :tap + │ ├── message_loc: (7,0)-(7,3) = "tap" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: + │ @ BlockNode (location: (7,4)-(7,19)) + │ ├── flags: ∅ + │ ├── locals: [:it] + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (7,6)-(7,17)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 2) + │ │ ├── @ CallNode (location: (7,6)-(7,8)) + │ │ │ ├── flags: newline, variable_call, ignore_visibility + │ │ │ ├── receiver: ∅ + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── name: :it + │ │ │ ├── message_loc: (7,6)-(7,8) = "it" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: ∅ + │ │ │ ├── closing_loc: ∅ + │ │ │ └── block: ∅ + │ │ └── @ LocalVariableOperatorWriteNode (location: (7,10)-(7,17)) + │ │ ├── flags: newline + │ │ ├── name_loc: (7,10)-(7,12) = "it" + │ │ ├── binary_operator_loc: (7,13)-(7,15) = "+=" + │ │ ├── value: + │ │ │ @ IntegerNode (location: (7,16)-(7,17)) + │ │ │ ├── flags: static_literal, decimal + │ │ │ └── value: 1 + │ │ ├── name: :it + │ │ ├── binary_operator: :+ + │ │ └── depth: 0 + │ ├── opening_loc: (7,4)-(7,5) = "{" + │ └── closing_loc: (7,18)-(7,19) = "}" + ├── @ CallNode (location: (9,0)-(9,20)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :tap + │ ├── message_loc: (9,0)-(9,3) = "tap" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: + │ @ BlockNode (location: (9,4)-(9,20)) + │ ├── flags: ∅ + │ ├── locals: [:it] + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (9,6)-(9,18)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 2) + │ │ ├── @ CallNode (location: (9,6)-(9,8)) + │ │ │ ├── flags: newline, variable_call, ignore_visibility + │ │ │ ├── receiver: ∅ + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── name: :it + │ │ │ ├── message_loc: (9,6)-(9,8) = "it" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: ∅ + │ │ │ ├── closing_loc: ∅ + │ │ │ └── block: ∅ + │ │ └── @ LocalVariableOrWriteNode (location: (9,10)-(9,18)) + │ │ ├── flags: newline + │ │ ├── name_loc: (9,10)-(9,12) = "it" + │ │ ├── operator_loc: (9,13)-(9,16) = "||=" + │ │ ├── value: + │ │ │ @ IntegerNode (location: (9,17)-(9,18)) + │ │ │ ├── flags: static_literal, decimal + │ │ │ └── value: 1 + │ │ ├── name: :it + │ │ └── depth: 0 + │ ├── opening_loc: (9,4)-(9,5) = "{" + │ └── closing_loc: (9,19)-(9,20) = "}" + ├── @ CallNode (location: (11,0)-(11,20)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :tap + │ ├── message_loc: (11,0)-(11,3) = "tap" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: + │ @ BlockNode (location: (11,4)-(11,20)) + │ ├── flags: ∅ + │ ├── locals: [:it] + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (11,6)-(11,18)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 2) + │ │ ├── @ CallNode (location: (11,6)-(11,8)) + │ │ │ ├── flags: newline, variable_call, ignore_visibility + │ │ │ ├── receiver: ∅ + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── name: :it + │ │ │ ├── message_loc: (11,6)-(11,8) = "it" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: ∅ + │ │ │ ├── closing_loc: ∅ + │ │ │ └── block: ∅ + │ │ └── @ LocalVariableAndWriteNode (location: (11,10)-(11,18)) + │ │ ├── flags: newline + │ │ ├── name_loc: (11,10)-(11,12) = "it" + │ │ ├── operator_loc: (11,13)-(11,16) = "&&=" + │ │ ├── value: + │ │ │ @ IntegerNode (location: (11,17)-(11,18)) + │ │ │ ├── flags: static_literal, decimal + │ │ │ └── value: 1 + │ │ ├── name: :it + │ │ └── depth: 0 + │ ├── opening_loc: (11,4)-(11,5) = "{" + │ └── closing_loc: (11,19)-(11,20) = "}" + ├── @ CallNode (location: (13,0)-(13,19)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :tap + │ ├── message_loc: (13,0)-(13,3) = "tap" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: + │ @ BlockNode (location: (13,4)-(13,19)) + │ ├── flags: ∅ + │ ├── locals: [:it] + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (13,6)-(13,17)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 2) + │ │ ├── @ LocalVariableOperatorWriteNode (location: (13,6)-(13,13)) + │ │ │ ├── flags: newline + │ │ │ ├── name_loc: (13,6)-(13,8) = "it" + │ │ │ ├── binary_operator_loc: (13,9)-(13,11) = "+=" + │ │ │ ├── value: + │ │ │ │ @ IntegerNode (location: (13,12)-(13,13)) + │ │ │ │ ├── flags: static_literal, decimal + │ │ │ │ └── value: 1 + │ │ │ ├── name: :it + │ │ │ ├── binary_operator: :+ + │ │ │ └── depth: 0 + │ │ └── @ LocalVariableReadNode (location: (13,15)-(13,17)) + │ │ ├── flags: newline + │ │ ├── name: :it + │ │ └── depth: 0 + │ ├── opening_loc: (13,4)-(13,5) = "{" + │ └── closing_loc: (13,18)-(13,19) = "}" + ├── @ CallNode (location: (15,0)-(15,20)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :tap + │ ├── message_loc: (15,0)-(15,3) = "tap" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: + │ @ BlockNode (location: (15,4)-(15,20)) + │ ├── flags: ∅ + │ ├── locals: [:it] + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (15,6)-(15,18)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 2) + │ │ ├── @ LocalVariableOrWriteNode (location: (15,6)-(15,14)) + │ │ │ ├── flags: newline + │ │ │ ├── name_loc: (15,6)-(15,8) = "it" + │ │ │ ├── operator_loc: (15,9)-(15,12) = "||=" + │ │ │ ├── value: + │ │ │ │ @ IntegerNode (location: (15,13)-(15,14)) + │ │ │ │ ├── flags: static_literal, decimal + │ │ │ │ └── value: 1 + │ │ │ ├── name: :it + │ │ │ └── depth: 0 + │ │ └── @ LocalVariableReadNode (location: (15,16)-(15,18)) + │ │ ├── flags: newline + │ │ ├── name: :it + │ │ └── depth: 0 + │ ├── opening_loc: (15,4)-(15,5) = "{" + │ └── closing_loc: (15,19)-(15,20) = "}" + ├── @ CallNode (location: (17,0)-(17,20)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :tap + │ ├── message_loc: (17,0)-(17,3) = "tap" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: + │ @ BlockNode (location: (17,4)-(17,20)) + │ ├── flags: ∅ + │ ├── locals: [:it] + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (17,6)-(17,18)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 2) + │ │ ├── @ LocalVariableAndWriteNode (location: (17,6)-(17,14)) + │ │ │ ├── flags: newline + │ │ │ ├── name_loc: (17,6)-(17,8) = "it" + │ │ │ ├── operator_loc: (17,9)-(17,12) = "&&=" + │ │ │ ├── value: + │ │ │ │ @ IntegerNode (location: (17,13)-(17,14)) + │ │ │ │ ├── flags: static_literal, decimal + │ │ │ │ └── value: 1 + │ │ │ ├── name: :it + │ │ │ └── depth: 0 + │ │ └── @ LocalVariableReadNode (location: (17,16)-(17,18)) + │ │ ├── flags: newline + │ │ ├── name: :it + │ │ └── depth: 0 + │ ├── opening_loc: (17,4)-(17,5) = "{" + │ └── closing_loc: (17,19)-(17,20) = "}" + ├── @ CallNode (location: (19,0)-(19,23)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :tap + │ ├── message_loc: (19,0)-(19,3) = "tap" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: + │ @ BlockNode (location: (19,4)-(19,23)) + │ ├── flags: ∅ + │ ├── locals: [:it] + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (19,6)-(19,21)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 3) + │ │ ├── @ CallNode (location: (19,6)-(19,8)) + │ │ │ ├── flags: newline, variable_call, ignore_visibility + │ │ │ ├── receiver: ∅ + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── name: :it + │ │ │ ├── message_loc: (19,6)-(19,8) = "it" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: ∅ + │ │ │ ├── closing_loc: ∅ + │ │ │ └── block: ∅ + │ │ ├── @ LocalVariableOperatorWriteNode (location: (19,10)-(19,17)) + │ │ │ ├── flags: newline + │ │ │ ├── name_loc: (19,10)-(19,12) = "it" + │ │ │ ├── binary_operator_loc: (19,13)-(19,15) = "+=" + │ │ │ ├── value: + │ │ │ │ @ IntegerNode (location: (19,16)-(19,17)) + │ │ │ │ ├── flags: static_literal, decimal + │ │ │ │ └── value: 1 + │ │ │ ├── name: :it + │ │ │ ├── binary_operator: :+ + │ │ │ └── depth: 0 + │ │ └── @ LocalVariableReadNode (location: (19,19)-(19,21)) + │ │ ├── flags: newline + │ │ ├── name: :it + │ │ └── depth: 0 + │ ├── opening_loc: (19,4)-(19,5) = "{" + │ └── closing_loc: (19,22)-(19,23) = "}" + ├── @ CallNode (location: (21,0)-(21,24)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :tap + │ ├── message_loc: (21,0)-(21,3) = "tap" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: + │ @ BlockNode (location: (21,4)-(21,24)) + │ ├── flags: ∅ + │ ├── locals: [:it] + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (21,6)-(21,22)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 3) + │ │ ├── @ CallNode (location: (21,6)-(21,8)) + │ │ │ ├── flags: newline, variable_call, ignore_visibility + │ │ │ ├── receiver: ∅ + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── name: :it + │ │ │ ├── message_loc: (21,6)-(21,8) = "it" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: ∅ + │ │ │ ├── closing_loc: ∅ + │ │ │ └── block: ∅ + │ │ ├── @ LocalVariableOrWriteNode (location: (21,10)-(21,18)) + │ │ │ ├── flags: newline + │ │ │ ├── name_loc: (21,10)-(21,12) = "it" + │ │ │ ├── operator_loc: (21,13)-(21,16) = "||=" + │ │ │ ├── value: + │ │ │ │ @ IntegerNode (location: (21,17)-(21,18)) + │ │ │ │ ├── flags: static_literal, decimal + │ │ │ │ └── value: 1 + │ │ │ ├── name: :it + │ │ │ └── depth: 0 + │ │ └── @ LocalVariableReadNode (location: (21,20)-(21,22)) + │ │ ├── flags: newline + │ │ ├── name: :it + │ │ └── depth: 0 + │ ├── opening_loc: (21,4)-(21,5) = "{" + │ └── closing_loc: (21,23)-(21,24) = "}" + └── @ CallNode (location: (23,0)-(23,24)) + ├── flags: newline, ignore_visibility + ├── receiver: ∅ + ├── call_operator_loc: ∅ + ├── name: :tap + ├── message_loc: (23,0)-(23,3) = "tap" + ├── opening_loc: ∅ + ├── arguments: ∅ + ├── closing_loc: ∅ + └── block: + @ BlockNode (location: (23,4)-(23,24)) + ├── flags: ∅ + ├── locals: [:it] + ├── parameters: ∅ + ├── body: + │ @ StatementsNode (location: (23,6)-(23,22)) + │ ├── flags: ∅ + │ └── body: (length: 3) + │ ├── @ CallNode (location: (23,6)-(23,8)) + │ │ ├── flags: newline, variable_call, ignore_visibility + │ │ ├── receiver: ∅ + │ │ ├── call_operator_loc: ∅ + │ │ ├── name: :it + │ │ ├── message_loc: (23,6)-(23,8) = "it" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: ∅ + │ │ ├── closing_loc: ∅ + │ │ └── block: ∅ + │ ├── @ LocalVariableAndWriteNode (location: (23,10)-(23,18)) + │ │ ├── flags: newline + │ │ ├── name_loc: (23,10)-(23,12) = "it" + │ │ ├── operator_loc: (23,13)-(23,16) = "&&=" + │ │ ├── value: + │ │ │ @ IntegerNode (location: (23,17)-(23,18)) + │ │ │ ├── flags: static_literal, decimal + │ │ │ └── value: 1 + │ │ ├── name: :it + │ │ └── depth: 0 + │ └── @ LocalVariableReadNode (location: (23,20)-(23,22)) + │ ├── flags: newline + │ ├── name: :it + │ └── depth: 0 + ├── opening_loc: (23,4)-(23,5) = "{" + └── closing_loc: (23,23)-(23,24) = "}" diff --git a/snapshots/3.3-3.3/it_read_and_assignment.txt b/snapshots/3.3-3.3/it_read_and_assignment.txt new file mode 100644 index 0000000000..d30b9c2902 --- /dev/null +++ b/snapshots/3.3-3.3/it_read_and_assignment.txt @@ -0,0 +1,81 @@ +@ ProgramNode (location: (1,0)-(1,30)) +├── flags: ∅ +├── locals: [] +└── statements: + @ StatementsNode (location: (1,0)-(1,30)) + ├── flags: ∅ + └── body: (length: 1) + └── @ CallNode (location: (1,0)-(1,30)) + ├── flags: newline + ├── receiver: + │ @ IntegerNode (location: (1,0)-(1,2)) + │ ├── flags: static_literal, decimal + │ └── value: 42 + ├── call_operator_loc: (1,2)-(1,3) = "." + ├── name: :tap + ├── message_loc: (1,3)-(1,6) = "tap" + ├── opening_loc: ∅ + ├── arguments: ∅ + ├── closing_loc: ∅ + └── block: + @ BlockNode (location: (1,7)-(1,30)) + ├── flags: ∅ + ├── locals: [:it] + ├── parameters: ∅ + ├── body: + │ @ StatementsNode (location: (1,9)-(1,28)) + │ ├── flags: ∅ + │ └── body: (length: 3) + │ ├── @ CallNode (location: (1,9)-(1,13)) + │ │ ├── flags: newline, ignore_visibility + │ │ ├── receiver: ∅ + │ │ ├── call_operator_loc: ∅ + │ │ ├── name: :p + │ │ ├── message_loc: (1,9)-(1,10) = "p" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: + │ │ │ @ ArgumentsNode (location: (1,11)-(1,13)) + │ │ │ ├── flags: ∅ + │ │ │ └── arguments: (length: 1) + │ │ │ └── @ CallNode (location: (1,11)-(1,13)) + │ │ │ ├── flags: variable_call, ignore_visibility + │ │ │ ├── receiver: ∅ + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── name: :it + │ │ │ ├── message_loc: (1,11)-(1,13) = "it" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: ∅ + │ │ │ ├── closing_loc: ∅ + │ │ │ └── block: ∅ + │ │ ├── closing_loc: ∅ + │ │ └── block: ∅ + │ ├── @ LocalVariableWriteNode (location: (1,15)-(1,22)) + │ │ ├── flags: newline + │ │ ├── name: :it + │ │ ├── depth: 0 + │ │ ├── name_loc: (1,15)-(1,17) = "it" + │ │ ├── value: + │ │ │ @ LocalVariableReadNode (location: (1,20)-(1,22)) + │ │ │ ├── flags: ∅ + │ │ │ ├── name: :it + │ │ │ └── depth: 0 + │ │ └── operator_loc: (1,18)-(1,19) = "=" + │ └── @ CallNode (location: (1,24)-(1,28)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :p + │ ├── message_loc: (1,24)-(1,25) = "p" + │ ├── opening_loc: ∅ + │ ├── arguments: + │ │ @ ArgumentsNode (location: (1,26)-(1,28)) + │ │ ├── flags: ∅ + │ │ └── arguments: (length: 1) + │ │ └── @ LocalVariableReadNode (location: (1,26)-(1,28)) + │ │ ├── flags: ∅ + │ │ ├── name: :it + │ │ └── depth: 0 + │ ├── closing_loc: ∅ + │ └── block: ∅ + ├── opening_loc: (1,7)-(1,8) = "{" + └── closing_loc: (1,29)-(1,30) = "}" diff --git a/snapshots/3.3-3.3/it_with_ordinary_parameter.txt b/snapshots/3.3-3.3/it_with_ordinary_parameter.txt new file mode 100644 index 0000000000..ab3178de33 --- /dev/null +++ b/snapshots/3.3-3.3/it_with_ordinary_parameter.txt @@ -0,0 +1,43 @@ +@ ProgramNode (location: (1,0)-(1,14)) +├── flags: ∅ +├── locals: [] +└── statements: + @ StatementsNode (location: (1,0)-(1,14)) + ├── flags: ∅ + └── body: (length: 1) + └── @ CallNode (location: (1,0)-(1,14)) + ├── flags: newline, ignore_visibility + ├── receiver: ∅ + ├── call_operator_loc: ∅ + ├── name: :proc + ├── message_loc: (1,0)-(1,4) = "proc" + ├── opening_loc: ∅ + ├── arguments: ∅ + ├── closing_loc: ∅ + └── block: + @ BlockNode (location: (1,5)-(1,14)) + ├── flags: ∅ + ├── locals: [] + ├── parameters: + │ @ BlockParametersNode (location: (1,7)-(1,9)) + │ ├── flags: ∅ + │ ├── parameters: ∅ + │ ├── locals: (length: 0) + │ ├── opening_loc: (1,7)-(1,8) = "|" + │ └── closing_loc: (1,8)-(1,9) = "|" + ├── body: + │ @ StatementsNode (location: (1,10)-(1,12)) + │ ├── flags: ∅ + │ └── body: (length: 1) + │ └── @ CallNode (location: (1,10)-(1,12)) + │ ├── flags: newline, variable_call, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :it + │ ├── message_loc: (1,10)-(1,12) = "it" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: ∅ + ├── opening_loc: (1,5)-(1,6) = "{" + └── closing_loc: (1,13)-(1,14) = "}" diff --git a/snapshots/3.3-3.3/keyword_args_in_array_assignment.txt b/snapshots/3.3-3.3/keyword_args_in_array_assignment.txt new file mode 100644 index 0000000000..785542a3e5 --- /dev/null +++ b/snapshots/3.3-3.3/keyword_args_in_array_assignment.txt @@ -0,0 +1,56 @@ +@ ProgramNode (location: (1,0)-(1,23)) +├── flags: ∅ +├── locals: [] +└── statements: + @ StatementsNode (location: (1,0)-(1,23)) + ├── flags: ∅ + └── body: (length: 1) + └── @ CallNode (location: (1,0)-(1,23)) + ├── flags: newline, attribute_write + ├── receiver: + │ @ CallNode (location: (1,0)-(1,6)) + │ ├── flags: variable_call, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :matrix + │ ├── message_loc: (1,0)-(1,6) = "matrix" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: ∅ + ├── call_operator_loc: ∅ + ├── name: :[]= + ├── message_loc: (1,6)-(1,19) = "[5, axis: :y]" + ├── opening_loc: (1,6)-(1,7) = "[" + ├── arguments: + │ @ ArgumentsNode (location: (1,7)-(1,23)) + │ ├── flags: contains_keywords + │ └── arguments: (length: 3) + │ ├── @ IntegerNode (location: (1,7)-(1,8)) + │ │ ├── flags: static_literal, decimal + │ │ └── value: 5 + │ ├── @ KeywordHashNode (location: (1,10)-(1,18)) + │ │ ├── flags: symbol_keys + │ │ └── elements: (length: 1) + │ │ └── @ AssocNode (location: (1,10)-(1,18)) + │ │ ├── flags: static_literal + │ │ ├── key: + │ │ │ @ SymbolNode (location: (1,10)-(1,15)) + │ │ │ ├── flags: static_literal, forced_us_ascii_encoding + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── value_loc: (1,10)-(1,14) = "axis" + │ │ │ ├── closing_loc: (1,14)-(1,15) = ":" + │ │ │ └── unescaped: "axis" + │ │ ├── value: + │ │ │ @ SymbolNode (location: (1,16)-(1,18)) + │ │ │ ├── flags: static_literal, forced_us_ascii_encoding + │ │ │ ├── opening_loc: (1,16)-(1,17) = ":" + │ │ │ ├── value_loc: (1,17)-(1,18) = "y" + │ │ │ ├── closing_loc: ∅ + │ │ │ └── unescaped: "y" + │ │ └── operator_loc: ∅ + │ └── @ IntegerNode (location: (1,22)-(1,23)) + │ ├── flags: static_literal, decimal + │ └── value: 8 + ├── closing_loc: (1,18)-(1,19) = "]" + └── block: ∅ diff --git a/snapshots/3.3-3.3/return_in_sclass.txt b/snapshots/3.3-3.3/return_in_sclass.txt new file mode 100644 index 0000000000..d8f298b23a --- /dev/null +++ b/snapshots/3.3-3.3/return_in_sclass.txt @@ -0,0 +1,25 @@ +@ ProgramNode (location: (1,0)-(1,23)) +├── flags: ∅ +├── locals: [] +└── statements: + @ StatementsNode (location: (1,0)-(1,23)) + ├── flags: ∅ + └── body: (length: 1) + └── @ SingletonClassNode (location: (1,0)-(1,23)) + ├── flags: newline + ├── locals: [] + ├── class_keyword_loc: (1,0)-(1,5) = "class" + ├── operator_loc: (1,6)-(1,8) = "<<" + ├── expression: + │ @ ConstantReadNode (location: (1,9)-(1,10)) + │ ├── flags: ∅ + │ └── name: :A + ├── body: + │ @ StatementsNode (location: (1,12)-(1,18)) + │ ├── flags: ∅ + │ └── body: (length: 1) + │ └── @ ReturnNode (location: (1,12)-(1,18)) + │ ├── flags: newline + │ ├── keyword_loc: (1,12)-(1,18) = "return" + │ └── arguments: ∅ + └── end_keyword_loc: (1,20)-(1,23) = "end" diff --git a/snapshots/3.4/circular_parameters.txt b/snapshots/3.4/circular_parameters.txt new file mode 100644 index 0000000000..3e74882f6c --- /dev/null +++ b/snapshots/3.4/circular_parameters.txt @@ -0,0 +1,167 @@ +@ ProgramNode (location: (1,0)-(4,19)) +├── flags: ∅ +├── locals: [] +└── statements: + @ StatementsNode (location: (1,0)-(4,19)) + ├── flags: ∅ + └── body: (length: 4) + ├── @ DefNode (location: (1,0)-(1,23)) + │ ├── flags: newline + │ ├── name: :foo + │ ├── name_loc: (1,4)-(1,7) = "foo" + │ ├── receiver: ∅ + │ ├── parameters: + │ │ @ ParametersNode (location: (1,8)-(1,17)) + │ │ ├── flags: ∅ + │ │ ├── requireds: (length: 0) + │ │ ├── optionals: (length: 1) + │ │ │ └── @ OptionalParameterNode (location: (1,8)-(1,17)) + │ │ │ ├── flags: ∅ + │ │ │ ├── name: :bar + │ │ │ ├── name_loc: (1,8)-(1,11) = "bar" + │ │ │ ├── operator_loc: (1,12)-(1,13) = "=" + │ │ │ └── value: + │ │ │ @ LocalVariableReadNode (location: (1,14)-(1,17)) + │ │ │ ├── flags: ∅ + │ │ │ ├── name: :bar + │ │ │ └── depth: 0 + │ │ ├── rest: ∅ + │ │ ├── posts: (length: 0) + │ │ ├── keywords: (length: 0) + │ │ ├── keyword_rest: ∅ + │ │ └── block: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (1,21)-(1,23)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 1) + │ │ └── @ IntegerNode (location: (1,21)-(1,23)) + │ │ ├── flags: static_literal, decimal + │ │ └── value: 42 + │ ├── locals: [:bar] + │ ├── def_keyword_loc: (1,0)-(1,3) = "def" + │ ├── operator_loc: ∅ + │ ├── lparen_loc: (1,7)-(1,8) = "(" + │ ├── rparen_loc: (1,17)-(1,18) = ")" + │ ├── equal_loc: (1,19)-(1,20) = "=" + │ └── end_keyword_loc: ∅ + ├── @ DefNode (location: (2,0)-(2,22)) + │ ├── flags: newline + │ ├── name: :foo + │ ├── name_loc: (2,4)-(2,7) = "foo" + │ ├── receiver: ∅ + │ ├── parameters: + │ │ @ ParametersNode (location: (2,8)-(2,16)) + │ │ ├── flags: ∅ + │ │ ├── requireds: (length: 0) + │ │ ├── optionals: (length: 0) + │ │ ├── rest: ∅ + │ │ ├── posts: (length: 0) + │ │ ├── keywords: (length: 1) + │ │ │ └── @ OptionalKeywordParameterNode (location: (2,8)-(2,16)) + │ │ │ ├── flags: ∅ + │ │ │ ├── name: :bar + │ │ │ ├── name_loc: (2,8)-(2,12) = "bar:" + │ │ │ └── value: + │ │ │ @ LocalVariableReadNode (location: (2,13)-(2,16)) + │ │ │ ├── flags: ∅ + │ │ │ ├── name: :bar + │ │ │ └── depth: 0 + │ │ ├── keyword_rest: ∅ + │ │ └── block: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (2,20)-(2,22)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 1) + │ │ └── @ IntegerNode (location: (2,20)-(2,22)) + │ │ ├── flags: static_literal, decimal + │ │ └── value: 42 + │ ├── locals: [:bar] + │ ├── def_keyword_loc: (2,0)-(2,3) = "def" + │ ├── operator_loc: ∅ + │ ├── lparen_loc: (2,7)-(2,8) = "(" + │ ├── rparen_loc: (2,16)-(2,17) = ")" + │ ├── equal_loc: (2,18)-(2,19) = "=" + │ └── end_keyword_loc: ∅ + ├── @ CallNode (location: (3,0)-(3,20)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :proc + │ ├── message_loc: (3,0)-(3,4) = "proc" + │ ├── opening_loc: ∅ + │ ├── arguments: ∅ + │ ├── closing_loc: ∅ + │ └── block: + │ @ BlockNode (location: (3,5)-(3,20)) + │ ├── flags: ∅ + │ ├── locals: [:foo] + │ ├── parameters: + │ │ @ BlockParametersNode (location: (3,7)-(3,18)) + │ │ ├── flags: ∅ + │ │ ├── parameters: + │ │ │ @ ParametersNode (location: (3,8)-(3,17)) + │ │ │ ├── flags: ∅ + │ │ │ ├── requireds: (length: 0) + │ │ │ ├── optionals: (length: 1) + │ │ │ │ └── @ OptionalParameterNode (location: (3,8)-(3,17)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ ├── name: :foo + │ │ │ │ ├── name_loc: (3,8)-(3,11) = "foo" + │ │ │ │ ├── operator_loc: (3,12)-(3,13) = "=" + │ │ │ │ └── value: + │ │ │ │ @ LocalVariableReadNode (location: (3,14)-(3,17)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ ├── name: :foo + │ │ │ │ └── depth: 0 + │ │ │ ├── rest: ∅ + │ │ │ ├── posts: (length: 0) + │ │ │ ├── keywords: (length: 0) + │ │ │ ├── keyword_rest: ∅ + │ │ │ └── block: ∅ + │ │ ├── locals: (length: 0) + │ │ ├── opening_loc: (3,7)-(3,8) = "|" + │ │ └── closing_loc: (3,17)-(3,18) = "|" + │ ├── body: ∅ + │ ├── opening_loc: (3,5)-(3,6) = "{" + │ └── closing_loc: (3,19)-(3,20) = "}" + └── @ CallNode (location: (4,0)-(4,19)) + ├── flags: newline, ignore_visibility + ├── receiver: ∅ + ├── call_operator_loc: ∅ + ├── name: :proc + ├── message_loc: (4,0)-(4,4) = "proc" + ├── opening_loc: ∅ + ├── arguments: ∅ + ├── closing_loc: ∅ + └── block: + @ BlockNode (location: (4,5)-(4,19)) + ├── flags: ∅ + ├── locals: [:foo] + ├── parameters: + │ @ BlockParametersNode (location: (4,7)-(4,17)) + │ ├── flags: ∅ + │ ├── parameters: + │ │ @ ParametersNode (location: (4,8)-(4,16)) + │ │ ├── flags: ∅ + │ │ ├── requireds: (length: 0) + │ │ ├── optionals: (length: 0) + │ │ ├── rest: ∅ + │ │ ├── posts: (length: 0) + │ │ ├── keywords: (length: 1) + │ │ │ └── @ OptionalKeywordParameterNode (location: (4,8)-(4,16)) + │ │ │ ├── flags: ∅ + │ │ │ ├── name: :foo + │ │ │ ├── name_loc: (4,8)-(4,12) = "foo:" + │ │ │ └── value: + │ │ │ @ LocalVariableReadNode (location: (4,13)-(4,16)) + │ │ │ ├── flags: ∅ + │ │ │ ├── name: :foo + │ │ │ └── depth: 0 + │ │ ├── keyword_rest: ∅ + │ │ └── block: ∅ + │ ├── locals: (length: 0) + │ ├── opening_loc: (4,7)-(4,8) = "|" + │ └── closing_loc: (4,16)-(4,17) = "|" + ├── body: ∅ + ├── opening_loc: (4,5)-(4,6) = "{" + └── closing_loc: (4,18)-(4,19) = "}" diff --git a/snapshots/it.txt b/snapshots/3.4/it.txt similarity index 100% rename from snapshots/it.txt rename to snapshots/3.4/it.txt diff --git a/snapshots/3.4/it_assignment.txt b/snapshots/3.4/it_assignment.txt new file mode 100644 index 0000000000..83469791c0 --- /dev/null +++ b/snapshots/3.4/it_assignment.txt @@ -0,0 +1,58 @@ +@ ProgramNode (location: (1,0)-(1,24)) +├── flags: ∅ +├── locals: [] +└── statements: + @ StatementsNode (location: (1,0)-(1,24)) + ├── flags: ∅ + └── body: (length: 1) + └── @ CallNode (location: (1,0)-(1,24)) + ├── flags: newline + ├── receiver: + │ @ IntegerNode (location: (1,0)-(1,2)) + │ ├── flags: static_literal, decimal + │ └── value: 42 + ├── call_operator_loc: (1,2)-(1,3) = "." + ├── name: :tap + ├── message_loc: (1,3)-(1,6) = "tap" + ├── opening_loc: ∅ + ├── arguments: ∅ + ├── closing_loc: ∅ + └── block: + @ BlockNode (location: (1,7)-(1,24)) + ├── flags: ∅ + ├── locals: [:it] + ├── parameters: ∅ + ├── body: + │ @ StatementsNode (location: (1,9)-(1,22)) + │ ├── flags: ∅ + │ └── body: (length: 2) + │ ├── @ LocalVariableWriteNode (location: (1,9)-(1,16)) + │ │ ├── flags: newline + │ │ ├── name: :it + │ │ ├── depth: 0 + │ │ ├── name_loc: (1,9)-(1,11) = "it" + │ │ ├── value: + │ │ │ @ LocalVariableReadNode (location: (1,14)-(1,16)) + │ │ │ ├── flags: ∅ + │ │ │ ├── name: :it + │ │ │ └── depth: 0 + │ │ └── operator_loc: (1,12)-(1,13) = "=" + │ └── @ CallNode (location: (1,18)-(1,22)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :p + │ ├── message_loc: (1,18)-(1,19) = "p" + │ ├── opening_loc: ∅ + │ ├── arguments: + │ │ @ ArgumentsNode (location: (1,20)-(1,22)) + │ │ ├── flags: ∅ + │ │ └── arguments: (length: 1) + │ │ └── @ LocalVariableReadNode (location: (1,20)-(1,22)) + │ │ ├── flags: ∅ + │ │ ├── name: :it + │ │ └── depth: 0 + │ ├── closing_loc: ∅ + │ └── block: ∅ + ├── opening_loc: (1,7)-(1,8) = "{" + └── closing_loc: (1,23)-(1,24) = "}" diff --git a/snapshots/it_indirect_writes.txt b/snapshots/3.4/it_indirect_writes.txt similarity index 100% rename from snapshots/it_indirect_writes.txt rename to snapshots/3.4/it_indirect_writes.txt diff --git a/snapshots/it_read_and_assignment.txt b/snapshots/3.4/it_read_and_assignment.txt similarity index 100% rename from snapshots/it_read_and_assignment.txt rename to snapshots/3.4/it_read_and_assignment.txt diff --git a/snapshots/endless_methods_command_call.txt b/snapshots/3.5/endless_methods_command_call.txt similarity index 100% rename from snapshots/endless_methods_command_call.txt rename to snapshots/3.5/endless_methods_command_call.txt diff --git a/snapshots/leading_logical.txt b/snapshots/3.5/leading_logical.txt similarity index 100% rename from snapshots/leading_logical.txt rename to snapshots/3.5/leading_logical.txt diff --git a/src/prism.c b/src/prism.c index 0ebcae62f9..95e7d09050 100644 --- a/src/prism.c +++ b/src/prism.c @@ -15764,7 +15764,7 @@ parse_return(pm_parser_t *parser, pm_node_t *node) { break; } } - if (in_sclass) { + if (in_sclass && parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) { pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID); } } diff --git a/test/prism/errors/3.3-3.3/circular_parameters.txt b/test/prism/errors/3.3-3.3/circular_parameters.txt new file mode 100644 index 0000000000..ef9642b075 --- /dev/null +++ b/test/prism/errors/3.3-3.3/circular_parameters.txt @@ -0,0 +1,12 @@ +def foo(bar = bar) = 42 + ^~~ circular argument reference - bar + +def foo(bar: bar) = 42 + ^~~ circular argument reference - bar + +proc { |foo = foo| } + ^~~ circular argument reference - foo + +proc { |foo: foo| } + ^~~ circular argument reference - foo + diff --git a/test/prism/errors/3.3-3.4/leading_logical.txt b/test/prism/errors/3.3-3.4/leading_logical.txt new file mode 100644 index 0000000000..2a702e281d --- /dev/null +++ b/test/prism/errors/3.3-3.4/leading_logical.txt @@ -0,0 +1,34 @@ +1 +&& 2 +^~ unexpected '&&', ignoring it +&& 3 +^~ unexpected '&&', ignoring it + +1 +|| 2 +^ unexpected '|', ignoring it + ^ unexpected '|', ignoring it +|| 3 +^ unexpected '|', ignoring it + ^ unexpected '|', ignoring it + +1 +and 2 +^~~ unexpected 'and', ignoring it +and 3 +^~~ unexpected 'and', ignoring it + +1 +or 2 +^~ unexpected 'or', ignoring it +or 3 +^~ unexpected 'or', ignoring it + +1 +and foo +^~~ unexpected 'and', ignoring it + +2 +or foo +^~ unexpected 'or', ignoring it + diff --git a/test/prism/errors/3.3-3.4/private_endless_method.txt b/test/prism/errors/3.3-3.4/private_endless_method.txt new file mode 100644 index 0000000000..8aae5e0cd3 --- /dev/null +++ b/test/prism/errors/3.3-3.4/private_endless_method.txt @@ -0,0 +1,3 @@ +private def foo = puts "Hello" + ^ unexpected string literal, expecting end-of-input + diff --git a/test/prism/errors/block_args_in_array_assignment.txt b/test/prism/errors/3.4/block_args_in_array_assignment.txt similarity index 100% rename from test/prism/errors/block_args_in_array_assignment.txt rename to test/prism/errors/3.4/block_args_in_array_assignment.txt diff --git a/test/prism/errors/dont_allow_return_inside_sclass_body.txt b/test/prism/errors/3.4/dont_allow_return_inside_sclass_body.txt similarity index 100% rename from test/prism/errors/dont_allow_return_inside_sclass_body.txt rename to test/prism/errors/3.4/dont_allow_return_inside_sclass_body.txt diff --git a/test/prism/errors/it_with_ordinary_parameter.txt b/test/prism/errors/3.4/it_with_ordinary_parameter.txt similarity index 100% rename from test/prism/errors/it_with_ordinary_parameter.txt rename to test/prism/errors/3.4/it_with_ordinary_parameter.txt diff --git a/test/prism/errors/keyword_args_in_array_assignment.txt b/test/prism/errors/3.4/keyword_args_in_array_assignment.txt similarity index 100% rename from test/prism/errors/keyword_args_in_array_assignment.txt rename to test/prism/errors/3.4/keyword_args_in_array_assignment.txt diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb index 9dd4aea728..9abed92652 100644 --- a/test/prism/errors_test.rb +++ b/test/prism/errors_test.rb @@ -1,41 +1,19 @@ # frozen_string_literal: true +return if RUBY_VERSION < "3.3.0" + require_relative "test_helper" module Prism class ErrorsTest < TestCase base = File.expand_path("errors", __dir__) - filepaths = Dir["*.txt", base: base] - - if RUBY_VERSION < "3.0" - filepaths -= [ - "cannot_assign_to_a_reserved_numbered_parameter.txt", - "writing_numbered_parameter.txt", - "targeting_numbered_parameter.txt", - "defining_numbered_parameter.txt", - "defining_numbered_parameter_2.txt", - "numbered_parameters_in_block_arguments.txt", - "numbered_and_write.txt", - "numbered_or_write.txt", - "numbered_operator_write.txt" - ] - end - - if RUBY_VERSION < "3.4" - filepaths -= [ - "it_with_ordinary_parameter.txt", - "block_args_in_array_assignment.txt", - "keyword_args_in_array_assignment.txt" - ] - end - - if RUBY_VERSION < "3.4" || RUBY_RELEASE_DATE < "2024-07-24" - filepaths -= ["dont_allow_return_inside_sclass_body.txt"] - end + filepaths = Dir["**/*.txt", base: base] filepaths.each do |filepath| - define_method(:"test_#{File.basename(filepath, ".txt")}") do - assert_errors(File.join(base, filepath)) + ruby_versions_for(filepath).each do |version| + define_method(:"test_#{version}_#{File.basename(filepath, ".txt")}") do + assert_errors(File.join(base, filepath), version) + end end end @@ -86,38 +64,15 @@ def test_invalid_message_name assert_equal :"", Prism.parse_statement("+.@foo,+=foo").write_name end - def test_circular_parameters - source = <<~RUBY - def foo(bar = bar) = 42 - def foo(bar: bar) = 42 - proc { |foo = foo| } - proc { |foo: foo| } - RUBY - - source.each_line do |line| - assert_predicate Prism.parse(line, version: "3.3.0"), :failure? - assert_predicate Prism.parse(line), :success? - end - end - - def test_private_endless_method - source = <<~RUBY - private def foo = puts "Hello" - RUBY - - assert_predicate Prism.parse(source, version: "3.4"), :failure? - assert_predicate Prism.parse(source), :success? - end - private - def assert_errors(filepath) + def assert_errors(filepath, version) expected = File.read(filepath, binmode: true, external_encoding: Encoding::UTF_8) source = expected.lines.grep_v(/^\s*\^/).join.gsub(/\n*\z/, "") - refute_valid_syntax(source) + refute_valid_syntax(source) if current_major_minor == version - result = Prism.parse(source) + result = Prism.parse(source, version: version) errors = result.errors refute_empty errors, "Expected errors in #{filepath}" diff --git a/test/prism/fixtures/3.3-3.3/block_args_in_array_assignment.txt b/test/prism/fixtures/3.3-3.3/block_args_in_array_assignment.txt new file mode 100644 index 0000000000..6d6b052681 --- /dev/null +++ b/test/prism/fixtures/3.3-3.3/block_args_in_array_assignment.txt @@ -0,0 +1 @@ +matrix[5, &block] = 8 diff --git a/test/prism/fixtures/it.txt b/test/prism/fixtures/3.3-3.3/it.txt similarity index 100% rename from test/prism/fixtures/it.txt rename to test/prism/fixtures/3.3-3.3/it.txt diff --git a/test/prism/fixtures/it_indirect_writes.txt b/test/prism/fixtures/3.3-3.3/it_indirect_writes.txt similarity index 100% rename from test/prism/fixtures/it_indirect_writes.txt rename to test/prism/fixtures/3.3-3.3/it_indirect_writes.txt diff --git a/test/prism/fixtures/it_read_and_assignment.txt b/test/prism/fixtures/3.3-3.3/it_read_and_assignment.txt similarity index 100% rename from test/prism/fixtures/it_read_and_assignment.txt rename to test/prism/fixtures/3.3-3.3/it_read_and_assignment.txt diff --git a/test/prism/fixtures/3.3-3.3/it_with_ordinary_parameter.txt b/test/prism/fixtures/3.3-3.3/it_with_ordinary_parameter.txt new file mode 100644 index 0000000000..178b641e6b --- /dev/null +++ b/test/prism/fixtures/3.3-3.3/it_with_ordinary_parameter.txt @@ -0,0 +1 @@ +proc { || it } diff --git a/test/prism/fixtures/3.3-3.3/keyword_args_in_array_assignment.txt b/test/prism/fixtures/3.3-3.3/keyword_args_in_array_assignment.txt new file mode 100644 index 0000000000..88016c2afe --- /dev/null +++ b/test/prism/fixtures/3.3-3.3/keyword_args_in_array_assignment.txt @@ -0,0 +1 @@ +matrix[5, axis: :y] = 8 diff --git a/test/prism/fixtures/3.3-3.3/return_in_sclass.txt b/test/prism/fixtures/3.3-3.3/return_in_sclass.txt new file mode 100644 index 0000000000..f1fde5771a --- /dev/null +++ b/test/prism/fixtures/3.3-3.3/return_in_sclass.txt @@ -0,0 +1 @@ +class << A; return; end diff --git a/test/prism/fixtures/3.4/circular_parameters.txt b/test/prism/fixtures/3.4/circular_parameters.txt new file mode 100644 index 0000000000..11537023ad --- /dev/null +++ b/test/prism/fixtures/3.4/circular_parameters.txt @@ -0,0 +1,4 @@ +def foo(bar = bar) = 42 +def foo(bar: bar) = 42 +proc { |foo = foo| } +proc { |foo: foo| } diff --git a/test/prism/fixtures/3.4/it.txt b/test/prism/fixtures/3.4/it.txt new file mode 100644 index 0000000000..5410b01e71 --- /dev/null +++ b/test/prism/fixtures/3.4/it.txt @@ -0,0 +1,5 @@ +x do + it +end + +-> { it } diff --git a/test/prism/fixtures/3.4/it_indirect_writes.txt b/test/prism/fixtures/3.4/it_indirect_writes.txt new file mode 100644 index 0000000000..bb87e9483e --- /dev/null +++ b/test/prism/fixtures/3.4/it_indirect_writes.txt @@ -0,0 +1,23 @@ +tap { it += 1 } + +tap { it ||= 1 } + +tap { it &&= 1 } + +tap { it; it += 1 } + +tap { it; it ||= 1 } + +tap { it; it &&= 1 } + +tap { it += 1; it } + +tap { it ||= 1; it } + +tap { it &&= 1; it } + +tap { it; it += 1; it } + +tap { it; it ||= 1; it } + +tap { it; it &&= 1; it } diff --git a/test/prism/fixtures/3.4/it_read_and_assignment.txt b/test/prism/fixtures/3.4/it_read_and_assignment.txt new file mode 100644 index 0000000000..2cceeb2a54 --- /dev/null +++ b/test/prism/fixtures/3.4/it_read_and_assignment.txt @@ -0,0 +1 @@ +42.tap { p it; it = it; p it } diff --git a/test/prism/fixtures/endless_methods_command_call.txt b/test/prism/fixtures/3.5/endless_methods_command_call.txt similarity index 100% rename from test/prism/fixtures/endless_methods_command_call.txt rename to test/prism/fixtures/3.5/endless_methods_command_call.txt diff --git a/test/prism/fixtures/leading_logical.txt b/test/prism/fixtures/3.5/leading_logical.txt similarity index 100% rename from test/prism/fixtures/leading_logical.txt rename to test/prism/fixtures/3.5/leading_logical.txt diff --git a/test/prism/fixtures_test.rb b/test/prism/fixtures_test.rb index ddb6ffb40c..9d2acfdc1b 100644 --- a/test/prism/fixtures_test.rb +++ b/test/prism/fixtures_test.rb @@ -24,9 +24,13 @@ class FixturesTest < TestCase except << "whitequark/ruby_bug_19281.txt" end + if RUBY_VERSION < "3.4.0" + except << "3.4/circular_parameters.txt" + end + # Leaving these out until they are supported by parse.y. - except << "leading_logical.txt" - except << "endless_methods_command_call.txt" + except << "3.5/leading_logical.txt" + except << "3.5/endless_methods_command_call.txt" # https://bugs.ruby-lang.org/issues/21168#note-5 except << "command_method_call_2.txt" diff --git a/test/prism/lex_test.rb b/test/prism/lex_test.rb index 3a0da1a2d8..9682bf8a32 100644 --- a/test/prism/lex_test.rb +++ b/test/prism/lex_test.rb @@ -43,16 +43,16 @@ class LexTest < TestCase end # https://bugs.ruby-lang.org/issues/20925 - except << "leading_logical.txt" + except << "3.5/leading_logical.txt" # https://bugs.ruby-lang.org/issues/17398#note-12 - except << "endless_methods_command_call.txt" + except << "3.5/endless_methods_command_call.txt" # https://bugs.ruby-lang.org/issues/21168#note-5 except << "command_method_call_2.txt" - Fixture.each(except: except) do |fixture| - define_method(fixture.test_name) { assert_lex(fixture) } + Fixture.each_with_version(except: except) do |fixture, version| + define_method(fixture.test_name(version)) { assert_lex(fixture, version) } end def test_lex_file @@ -97,10 +97,12 @@ def test_parse_lex_file private - def assert_lex(fixture) + def assert_lex(fixture, version) + return unless current_major_minor == version + source = fixture.read - result = Prism.lex_compat(source) + result = Prism.lex_compat(source, version: version) assert_equal [], result.errors Prism.lex_ripper(source).zip(result.value).each do |(ripper, prism)| diff --git a/test/prism/locals_test.rb b/test/prism/locals_test.rb index 9a3224e8ef..d5def0d18f 100644 --- a/test/prism/locals_test.rb +++ b/test/prism/locals_test.rb @@ -32,8 +32,8 @@ class LocalsTest < TestCase "whitequark/ruby_bug_10653.txt", # Leaving these out until they are supported by parse.y. - "leading_logical.txt", - "endless_methods_command_call.txt", + "3.5/leading_logical.txt", + "3.5/endless_methods_command_call.txt", "command_method_call_2.txt" ] diff --git a/test/prism/ruby/parser_test.rb b/test/prism/ruby/parser_test.rb index 10b5fca5ea..016fda91f0 100644 --- a/test/prism/ruby/parser_test.rb +++ b/test/prism/ruby/parser_test.rb @@ -65,11 +65,14 @@ class ParserTest < TestCase # 1.. && 2 "ranges.txt", + # https://bugs.ruby-lang.org/issues/20478 + "3.4/circular_parameters.txt", + # Cannot yet handling leading logical operators. - "leading_logical.txt", + "3.5/leading_logical.txt", # Ruby >= 3.5 specific syntax - "endless_methods_command_call.txt", + "3.5/endless_methods_command_call.txt", # https://bugs.ruby-lang.org/issues/21168#note-5 "command_method_call_2.txt", @@ -165,9 +168,9 @@ def test_non_prism_builder_class_deprecated if RUBY_VERSION >= "3.3" def test_current_parser_for_current_ruby - major, minor, _patch = Gem::Version.new(RUBY_VERSION).segments + major, minor = current_major_minor.split(".") # Let's just hope there never is a Ruby 3.10 or similar - expected = major * 10 + minor + expected = major.to_i * 10 + minor.to_i assert_equal(expected, Translation::ParserCurrent.new.version) end end @@ -189,7 +192,7 @@ def test_invalid_syntax end def test_it_block_parameter_syntax - it_fixture_path = Pathname(__dir__).join("../../../test/prism/fixtures/it.txt") + it_fixture_path = Pathname(__dir__).join("../../../test/prism/fixtures/3.4/it.txt") buffer = Parser::Source::Buffer.new(it_fixture_path) buffer.source = it_fixture_path.read diff --git a/test/prism/ruby/ripper_test.rb b/test/prism/ruby/ripper_test.rb index 4916ec8d9d..12c854aea6 100644 --- a/test/prism/ruby/ripper_test.rb +++ b/test/prism/ruby/ripper_test.rb @@ -9,7 +9,7 @@ class RipperTest < TestCase # Skip these tests that Ripper is reporting the wrong results for. incorrect = [ # Not yet supported. - "leading_logical.txt", + "3.5/leading_logical.txt", # Ripper incorrectly attributes the block to the keyword. "seattlerb/block_break.txt", @@ -31,8 +31,16 @@ class RipperTest < TestCase # Ripper fails to understand some structures that span across heredocs. "spanning_heredoc.txt", + "3.3-3.3/block_args_in_array_assignment.txt", + "3.3-3.3/it_with_ordinary_parameter.txt", + "3.3-3.3/keyword_args_in_array_assignment.txt", + "3.3-3.3/return_in_sclass.txt", + + # https://bugs.ruby-lang.org/issues/20478 + "3.4/circular_parameters.txt", + # https://bugs.ruby-lang.org/issues/17398#note-12 - "endless_methods_command_call.txt", + "3.5/endless_methods_command_call.txt", # https://bugs.ruby-lang.org/issues/21168#note-5 "command_method_call_2.txt", diff --git a/test/prism/ruby/ruby_parser_test.rb b/test/prism/ruby/ruby_parser_test.rb index ec55e41967..7640ddaf1c 100644 --- a/test/prism/ruby/ruby_parser_test.rb +++ b/test/prism/ruby/ruby_parser_test.rb @@ -39,7 +39,6 @@ class RubyParserTest < TestCase "dos_endings.txt", "heredocs_with_fake_newlines.txt", "heredocs_with_ignored_newlines.txt", - "leading_logical.txt", "method_calls.txt", "methods.txt", "multi_write.txt", @@ -77,8 +76,15 @@ class RubyParserTest < TestCase "whitequark/ruby_bug_19281.txt", "whitequark/slash_newline_in_heredocs.txt", - # Ruby >= 3.5 specific syntax - "endless_methods_command_call.txt", + "3.3-3.3/block_args_in_array_assignment.txt", + "3.3-3.3/it_with_ordinary_parameter.txt", + "3.3-3.3/keyword_args_in_array_assignment.txt", + "3.3-3.3/return_in_sclass.txt", + + "3.4/circular_parameters.txt", + + "3.5/endless_methods_command_call.txt", + "3.5/leading_logical.txt", # https://bugs.ruby-lang.org/issues/21168#note-5 "command_method_call_2.txt", diff --git a/test/prism/snapshots_test.rb b/test/prism/snapshots_test.rb index 3fbda1f86e..20cdf44d90 100644 --- a/test/prism/snapshots_test.rb +++ b/test/prism/snapshots_test.rb @@ -36,16 +36,16 @@ def teardown ) end - Fixture.each(except: except) do |fixture| - define_method(fixture.test_name) { assert_snapshot(fixture) } + Fixture.each_with_version(except: except) do |fixture, version| + define_method(fixture.test_name(version)) { assert_snapshot(fixture, version) } end private - def assert_snapshot(fixture) + def assert_snapshot(fixture, version) source = fixture.read - result = Prism.parse(source, filepath: fixture.path) + result = Prism.parse(source, filepath: fixture.path, version: version) assert result.success? printed = PP.pp(result.value, +"", 79) @@ -57,8 +57,14 @@ def assert_snapshot(fixture) # If the snapshot file exists, but the printed value does not match the # snapshot, then update the snapshot file. if printed != saved - File.write(snapshot, printed) - warn("Updated snapshot at #{snapshot}.") + if ENV["UPDATE_SNAPSHOTS"] + File.write(snapshot, printed) + else + warn("Snapshot at #{snapshot} outdated for #{version}. Run with UPDATE_SNAPSHOTS=1 " \ + "to regenerate the files. If modifying behaviour for a subset of ruby versions, " \ + "instead move the fixture and snapshot into versioned directories. For more details, " \ + "see `Prism::TestCase.ruby_versions_for`.") + end end # If the snapshot file exists, then assert that the printed value diff --git a/test/prism/snippets_test.rb b/test/prism/snippets_test.rb index 66802c5dc3..3160442cc0 100644 --- a/test/prism/snippets_test.rb +++ b/test/prism/snippets_test.rb @@ -18,24 +18,24 @@ class SnippetsTest < TestCase "whitequark/multiple_pattern_matches.txt" ] - Fixture.each(except: except) do |fixture| - define_method(fixture.test_name) { assert_snippets(fixture) } + Fixture.each_with_version(except: except) do |fixture, version| + define_method(fixture.test_name(version)) { assert_snippets(fixture, version) } end private # We test every snippet (separated by \n\n) in isolation to ensure the # parser does not try to read bytes further than the end of each snippet. - def assert_snippets(fixture) + def assert_snippets(fixture, version) fixture.read.split(/(?<=\S)\n\n(?=\S)/).each do |snippet| snippet = snippet.rstrip - result = Prism.parse(snippet, filepath: fixture.path) + result = Prism.parse(snippet, filepath: fixture.path, version: version) assert result.success? if !ENV["PRISM_BUILD_MINIMAL"] - dumped = Prism.dump(snippet, filepath: fixture.path) - assert_equal_nodes(result.value, Prism.load(snippet, dumped).value) + dumped = Prism.dump(snippet, filepath: fixture.path, version: version) + assert_equal_nodes(result.value, Prism.load(snippet, dumped, version: version).value) end end end diff --git a/test/prism/test_helper.rb b/test/prism/test_helper.rb index 0be9d1e7da..84871722c9 100644 --- a/test/prism/test_helper.rb +++ b/test/prism/test_helper.rb @@ -58,8 +58,12 @@ def snapshot_path File.join(File.expand_path("../..", __dir__), "snapshots", path) end - def test_name - :"test_#{path}" + def test_name(version = nil) + if version + :"test_#{version}_#{path}" + else + :"test_#{path}" + end end def self.each(except: [], &block) @@ -68,6 +72,14 @@ def self.each(except: [], &block) paths.each { |path| yield Fixture.new(path) } end + def self.each_with_version(except: [], &block) + each(except: except) do |fixture| + TestCase.ruby_versions_for(fixture.path).each do |version| + yield fixture, version + end + end + end + def self.custom_base_path? ENV.key?("FIXTURE_BASE") end @@ -217,6 +229,37 @@ def self.windows? RbConfig::CONFIG["host_os"].match?(/bccwin|cygwin|djgpp|mingw|mswin|wince/i) end + # All versions that prism can parse + SYNTAX_VERSIONS = %w[3.3 3.4 3.5] + + # Returns an array of ruby versions that a given filepath should test against: + # test.txt # => all available versions + # 3.4/test.txt # => versions since 3.4 (inclusive) + # 3.4-4.2/test.txt # => verisions since 3.4 (inclusive) up to 4.2 (inclusive) + def self.ruby_versions_for(filepath) + return [ENV['SYNTAX_VERSION']] if ENV['SYNTAX_VERSION'] + + parts = filepath.split("/") + return SYNTAX_VERSIONS if parts.size == 1 + + version_start, version_stop = parts[0].split("-") + if version_stop + SYNTAX_VERSIONS[SYNTAX_VERSIONS.index(version_start)..SYNTAX_VERSIONS.index(version_stop)] + else + SYNTAX_VERSIONS[SYNTAX_VERSIONS.index(version_start)..] + end + end + + def current_major_minor + RUBY_VERSION.split(".")[0, 2].join(".") + end + + if RUBY_VERSION >= "3.3.0" + def test_all_syntax_versions_present + assert_include(SYNTAX_VERSIONS, current_major_minor) + end + end + private if RUBY_ENGINE == "ruby" && RubyVM::InstructionSequence.compile("").to_a[4][:parser] != :prism