summaryrefslogtreecommitdiff
path: root/test/prism
diff options
context:
space:
mode:
Diffstat (limited to 'test/prism')
-rw-r--r--test/prism/api/command_line_test.rb114
-rw-r--r--test/prism/api/dump_test.rb56
-rw-r--r--test/prism/api/freeze_test.rb65
-rw-r--r--test/prism/api/lex_test.rb23
-rw-r--r--test/prism/api/parse_comments_test.rb33
-rw-r--r--test/prism/api/parse_stream_test.rb118
-rw-r--r--test/prism/api/parse_success_test.rb16
-rw-r--r--test/prism/api/parse_test.rb189
-rw-r--r--test/prism/bom_test.rb60
-rw-r--r--test/prism/encoding/encodings_test.rb91
-rw-r--r--test/prism/encoding/regular_expression_encoding_test.rb115
-rw-r--r--test/prism/encoding/string_encoding_test.rb136
-rw-r--r--test/prism/encoding/symbol_encoding_test.rb108
-rw-r--r--test/prism/errors/1_2_3.txt11
-rw-r--r--test/prism/errors/3.3-3.3/circular_parameters.txt12
-rw-r--r--test/prism/errors/3.3-3.4/leading_logical.txt34
-rw-r--r--test/prism/errors/3.3-3.4/private_endless_method.txt3
-rw-r--r--test/prism/errors/3.3-4.0/do_not_allow_trailing_commas_in_method_parameters.txt3
-rw-r--r--test/prism/errors/3.3-4.0/noblock.txt6
-rw-r--r--test/prism/errors/3.3-4.0/singleton_method_with_void_value.txt3
-rw-r--r--test/prism/errors/3.4-4.0/void_value.txt18
-rw-r--r--test/prism/errors/3.4/block_args_in_array_assignment.txt3
-rw-r--r--test/prism/errors/3.4/dont_allow_return_inside_sclass_body.txt3
-rw-r--r--test/prism/errors/3.4/it_with_ordinary_parameter.txt3
-rw-r--r--test/prism/errors/3.4/keyword_args_in_array_assignment.txt3
-rw-r--r--test/prism/errors/4.1/do_not_allow_trailing_commas_after_terminating_arguments.txt6
-rw-r--r--test/prism/errors/4.1/end_block_exit.txt10
-rw-r--r--test/prism/errors/4.1/multiple_blocks.txt12
-rw-r--r--test/prism/errors/4.1/singleton_method_with_void_value.txt4
-rw-r--r--test/prism/errors/4.1/void_value.txt44
-rw-r--r--test/prism/errors/aliasing_global_variable_with_global_number_variable.txt3
-rw-r--r--test/prism/errors/aliasing_global_variable_with_non_global_variable.txt3
-rw-r--r--test/prism/errors/aliasing_non_global_variable_with_global_variable.txt3
-rw-r--r--test/prism/errors/alnum_delimiters.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_2.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_3.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_4.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_5.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_6.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_7.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_8.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_9.txt3
-rw-r--r--test/prism/errors/amperand_dot_after_endless_range.txt3
-rw-r--r--test/prism/errors/argument_after_ellipsis.txt3
-rw-r--r--test/prism/errors/argument_forwarding_only_effects_its_own_internals.txt3
-rw-r--r--test/prism/errors/argument_forwarding_when_parent_is_not_forwarding.txt3
-rw-r--r--test/prism/errors/arguments_after_block.txt17
-rw-r--r--test/prism/errors/arguments_binding_power_for_and.txt5
-rw-r--r--test/prism/errors/arguments_invalid_comma.txt4
-rw-r--r--test/prism/errors/arguments_splat_after_star_star.txt3
-rw-r--r--test/prism/errors/array_invalid_comma.txt4
-rw-r--r--test/prism/errors/array_with_double_commas.txt3
-rw-r--r--test/prism/errors/assign_to_numbered_parameter.txt11
-rw-r--r--test/prism/errors/bad_arguments.txt6
-rw-r--r--test/prism/errors/begin_at_toplevel.txt3
-rw-r--r--test/prism/errors/binary_range_with_left_unary_range.txt8
-rw-r--r--test/prism/errors/block_arg_and_block.txt3
-rw-r--r--test/prism/errors/block_args_with_endless_def.txt5
-rw-r--r--test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt5
-rw-r--r--test/prism/errors/block_pass_return_value.txt33
-rw-r--r--test/prism/errors/break_1.txt4
-rw-r--r--test/prism/errors/break_1_2_3.txt8
-rw-r--r--test/prism/errors/call_with_block_and_write.txt4
-rw-r--r--test/prism/errors/call_with_block_operator_write.txt4
-rw-r--r--test/prism/errors/call_with_block_or_write.txt4
-rw-r--r--test/prism/errors/cannot_assign_to_a_reserved_numbered_parameter.txt14
-rw-r--r--test/prism/errors/case_without_clauses.txt4
-rw-r--r--test/prism/errors/case_without_when_clauses_errors_on_else_clause.txt5
-rw-r--r--test/prism/errors/check_value_expression.txt20
-rw-r--r--test/prism/errors/class_definition_in_method_body.txt3
-rw-r--r--test/prism/errors/class_definition_in_method_defs.txt7
-rw-r--r--test/prism/errors/class_name.txt3
-rw-r--r--test/prism/errors/command_call_in.txt6
-rw-r--r--test/prism/errors/command_call_in_2.txt4
-rw-r--r--test/prism/errors/command_call_in_3.txt4
-rw-r--r--test/prism/errors/command_call_in_4.txt4
-rw-r--r--test/prism/errors/command_call_in_5.txt4
-rw-r--r--test/prism/errors/command_call_in_6.txt4
-rw-r--r--test/prism/errors/command_call_in_7.txt4
-rw-r--r--test/prism/errors/command_call_value_and.txt3
-rw-r--r--test/prism/errors/command_call_value_or.txt3
-rw-r--r--test/prism/errors/command_calls.txt10
-rw-r--r--test/prism/errors/command_calls_10.txt3
-rw-r--r--test/prism/errors/command_calls_11.txt3
-rw-r--r--test/prism/errors/command_calls_12.txt3
-rw-r--r--test/prism/errors/command_calls_13.txt3
-rw-r--r--test/prism/errors/command_calls_14.txt3
-rw-r--r--test/prism/errors/command_calls_15.txt3
-rw-r--r--test/prism/errors/command_calls_16.txt3
-rw-r--r--test/prism/errors/command_calls_17.txt5
-rw-r--r--test/prism/errors/command_calls_18.txt3
-rw-r--r--test/prism/errors/command_calls_19.txt3
-rw-r--r--test/prism/errors/command_calls_2.txt6
-rw-r--r--test/prism/errors/command_calls_20.txt3
-rw-r--r--test/prism/errors/command_calls_21.txt5
-rw-r--r--test/prism/errors/command_calls_22.txt3
-rw-r--r--test/prism/errors/command_calls_23.txt3
-rw-r--r--test/prism/errors/command_calls_24.txt5
-rw-r--r--test/prism/errors/command_calls_25.txt8
-rw-r--r--test/prism/errors/command_calls_26.txt3
-rw-r--r--test/prism/errors/command_calls_27.txt3
-rw-r--r--test/prism/errors/command_calls_28.txt3
-rw-r--r--test/prism/errors/command_calls_29.txt3
-rw-r--r--test/prism/errors/command_calls_3.txt3
-rw-r--r--test/prism/errors/command_calls_30.txt3
-rw-r--r--test/prism/errors/command_calls_31.txt17
-rw-r--r--test/prism/errors/command_calls_32.txt19
-rw-r--r--test/prism/errors/command_calls_33.txt6
-rw-r--r--test/prism/errors/command_calls_34.txt31
-rw-r--r--test/prism/errors/command_calls_35.txt50
-rw-r--r--test/prism/errors/command_calls_4.txt3
-rw-r--r--test/prism/errors/command_calls_5.txt3
-rw-r--r--test/prism/errors/command_calls_6.txt6
-rw-r--r--test/prism/errors/command_calls_7.txt6
-rw-r--r--test/prism/errors/command_calls_8.txt6
-rw-r--r--test/prism/errors/command_calls_9.txt6
-rw-r--r--test/prism/errors/conditional_predicate_closed.txt6
-rw-r--r--test/prism/errors/constant_assignment_in_method.txt3
-rw-r--r--test/prism/errors/constant_path_with_invalid_token_after.txt4
-rw-r--r--test/prism/errors/content_after_unterminated_heredoc.txt4
-rw-r--r--test/prism/errors/cr_without_lf_in_percent_expression.txt3
-rw-r--r--test/prism/errors/def_endless_do.txt6
-rw-r--r--test/prism/errors/def_ivar.txt3
-rw-r--r--test/prism/errors/def_with_empty_expression_receiver.txt3
-rw-r--r--test/prism/errors/def_with_expression_receiver_and_no_identifier.txt4
-rw-r--r--test/prism/errors/def_with_multiple_statements_receiver.txt10
-rw-r--r--test/prism/errors/def_with_optional_splat.txt6
-rw-r--r--test/prism/errors/defined_empty.txt3
-rw-r--r--test/prism/errors/defining_numbered_parameter.txt3
-rw-r--r--test/prism/errors/defining_numbered_parameter_2.txt3
-rw-r--r--test/prism/errors/defs_endless_method.txt12
-rw-r--r--test/prism/errors/destroy_call_operator_write_arguments.txt11
-rw-r--r--test/prism/errors/do_not_allow_characters_other_than_0_9_a_f_and_A_F_in_u_Unicode_character_notation.txt4
-rw-r--r--test/prism/errors/do_not_allow_forward_arguments_in_blocks.txt13
-rw-r--r--test/prism/errors/do_not_allow_forward_arguments_in_lambda_literals.txt13
-rw-r--r--test/prism/errors/do_not_allow_more_than_6_hexadecimal_digits_in_u_Unicode_character_notation.txt3
-rw-r--r--test/prism/errors/do_not_allow_multiple_codepoints_in_a_single_character_literal.txt3
-rw-r--r--test/prism/errors/do_not_allow_trailing_commas_in_lambda_parameters.txt3
-rw-r--r--test/prism/errors/dont_allow_return_inside_class_body.txt3
-rw-r--r--test/prism/errors/dont_allow_return_inside_module_body.txt3
-rw-r--r--test/prism/errors/dont_allow_setting_to_back_and_nth_reference.txt7
-rw-r--r--test/prism/errors/double_arguments_forwarding.txt4
-rw-r--r--test/prism/errors/double_scope_numbered_parameters.txt3
-rw-r--r--test/prism/errors/double_scope_repeated_numbered_parameters.txt3
-rw-r--r--test/prism/errors/double_splat_followed_by_splat_argument.txt3
-rw-r--r--test/prism/errors/double_splat_with_double_commas.txt3
-rw-r--r--test/prism/errors/duplicate_pattern_capture.txt17
-rw-r--r--test/prism/errors/duplicate_pattern_hash_key.txt4
-rw-r--r--test/prism/errors/duplicate_pattern_hash_key_2.txt3
-rw-r--r--test/prism/errors/duplicated_parameter_names.txt3
-rw-r--r--test/prism/errors/duplicated_parameter_names_2.txt3
-rw-r--r--test/prism/errors/duplicated_parameter_names_3.txt3
-rw-r--r--test/prism/errors/duplicated_parameter_names_4.txt3
-rw-r--r--test/prism/errors/duplicated_parameter_names_5.txt3
-rw-r--r--test/prism/errors/dynamic_label_pattern.txt3
-rw-r--r--test/prism/errors/ellipsis_in_no_paren_call.txt3
-rw-r--r--test/prism/errors/endless_method_command_call.txt3
-rw-r--r--test/prism/errors/endless_method_command_call_parameters.txt27
-rw-r--r--test/prism/errors/escape_unicode_curly_whitespace.txt5
-rw-r--r--test/prism/errors/for_loop_delimiter.txt3
-rw-r--r--test/prism/errors/for_loops_index_missing.txt5
-rw-r--r--test/prism/errors/for_loops_only_end.txt6
-rw-r--r--test/prism/errors/forwarding_arg_after_keyword_rest.txt3
-rw-r--r--test/prism/errors/forwarding_arg_and_block.txt3
-rw-r--r--test/prism/errors/heredoc_percent_q_newline_delimiter.txt11
-rw-r--r--test/prism/errors/heredoc_unterminated.txt9
-rw-r--r--test/prism/errors/incomplete_instance_var_string.txt4
-rw-r--r--test/prism/errors/index_call_with_block_and_write.txt5
-rw-r--r--test/prism/errors/index_call_with_block_operator_write.txt5
-rw-r--r--test/prism/errors/index_call_with_block_or_write.txt5
-rw-r--r--test/prism/errors/infix_after_label.txt6
-rw-r--r--test/prism/errors/interpolated_regular_expression_with_unknown_regexp_options.txt3
-rw-r--r--test/prism/errors/interpolated_symbol_pattern_hash_key.txt3
-rw-r--r--test/prism/errors/invalid_global_variable_write.txt4
-rw-r--r--test/prism/errors/invalid_hex_escape.txt3
-rw-r--r--test/prism/errors/invalid_multi_target.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_10.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_11.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_12.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_13.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_14.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_15.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_16.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_17.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_18.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_19.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_2.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_20.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_3.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_4.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_5.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_6.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_7.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_8.txt4
-rw-r--r--test/prism/errors/invalid_multi_target_9.txt4
-rw-r--r--test/prism/errors/invalid_number_underscores.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_10.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_11.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_12.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_2.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_3.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_4.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_5.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_6.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_7.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_8.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_9.txt3
-rw-r--r--test/prism/errors/invalid_operator_write_dot.txt3
-rw-r--r--test/prism/errors/invalid_operator_write_fcall.txt3
-rw-r--r--test/prism/errors/invalid_splat.txt4
-rw-r--r--test/prism/errors/keywords_parameters_before_required_parameters.txt4
-rw-r--r--test/prism/errors/label_in_interpolated_string.txt14
-rw-r--r--test/prism/errors/label_in_parentheses.txt3
-rw-r--r--test/prism/errors/loop_conditional_is_closed.txt4
-rw-r--r--test/prism/errors/match_plus.txt7
-rw-r--r--test/prism/errors/match_predicate_after_and_with_dot_method_call.txt3
-rw-r--r--test/prism/errors/match_predicate_after_and_with_opreator.txt3
-rw-r--r--test/prism/errors/match_predicate_after_or_with_dot_method_call.txt3
-rw-r--r--test/prism/errors/match_predicate_after_or_with_opreator.txt3
-rw-r--r--test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt4
-rw-r--r--test/prism/errors/match_predicate_after_rescue_with_opreator.txt4
-rw-r--r--test/prism/errors/match_required_after_and_with_dot_method_call.txt3
-rw-r--r--test/prism/errors/match_required_after_and_with_opreator.txt3
-rw-r--r--test/prism/errors/match_required_after_or_with_dot_method_call.txt3
-rw-r--r--test/prism/errors/match_required_after_or_with_opreator.txt3
-rw-r--r--test/prism/errors/match_required_after_rescue_with_dot_method_call.txt4
-rw-r--r--test/prism/errors/match_required_after_rescue_with_opreator.txt4
-rw-r--r--test/prism/errors/method_parameters_after_arguments_forwarding.txt4
-rw-r--r--test/prism/errors/method_parameters_after_block.txt4
-rw-r--r--test/prism/errors/method_with_arguments_after_anonymous_block.txt4
-rw-r--r--test/prism/errors/missing_terminator_in_parentheses.txt3
-rw-r--r--test/prism/errors/modifier_conditional_in_predicate.txt12
-rw-r--r--test/prism/errors/module_definition_in_method_body.txt3
-rw-r--r--test/prism/errors/module_definition_in_method_body_within_block.txt7
-rw-r--r--test/prism/errors/module_definition_in_method_defs.txt7
-rw-r--r--test/prism/errors/module_name_recoverable.txt4
-rw-r--r--test/prism/errors/multi_target_parens.txt19
-rw-r--r--test/prism/errors/multi_target_star.txt17
-rw-r--r--test/prism/errors/multiple_error_in_parameters_order.txt5
-rw-r--r--test/prism/errors/next_1.txt4
-rw-r--r--test/prism/errors/next_1_2_3.txt8
-rw-r--r--test/prism/errors/non_assoc_equality.txt25
-rw-r--r--test/prism/errors/non_assoc_range.txt5
-rw-r--r--test/prism/errors/not_without_parens_assignment.txt4
-rw-r--r--test/prism/errors/not_without_parens_call.txt7
-rw-r--r--test/prism/errors/not_without_parens_command.txt4
-rw-r--r--test/prism/errors/not_without_parens_command_call.txt4
-rw-r--r--test/prism/errors/not_without_parens_return.txt4
-rw-r--r--test/prism/errors/numbered_and_write.txt3
-rw-r--r--test/prism/errors/numbered_operator_write.txt3
-rw-r--r--test/prism/errors/numbered_or_write.txt3
-rw-r--r--test/prism/errors/numbered_parameters_in_block_arguments.txt3
-rw-r--r--test/prism/errors/optional_block_parameters_with_unary_operator.txt3
-rw-r--r--test/prism/errors/optional_block_parameters_with_unary_operator_2.txt3
-rw-r--r--test/prism/errors/optional_block_parameters_with_unary_operator_3.txt3
-rw-r--r--test/prism/errors/optional_block_parameters_with_unary_operator_4.txt3
-rw-r--r--test/prism/errors/parameter_name_ending_with_bang_or_question_mark.txt4
-rw-r--r--test/prism/errors/parameters_invalid_comma.txt4
-rw-r--r--test/prism/errors/pattern-capture-in-alt-array.txt4
-rw-r--r--test/prism/errors/pattern-capture-in-alt-hash.txt3
-rw-r--r--test/prism/errors/pattern-capture-in-alt-name.txt3
-rw-r--r--test/prism/errors/pattern-capture-in-alt-top.txt4
-rw-r--r--test/prism/errors/pattern_arithmetic_expressions.txt3
-rw-r--r--test/prism/errors/pattern_match_implicit_rest.txt3
-rw-r--r--test/prism/errors/pattern_string_key.txt8
-rw-r--r--test/prism/errors/pre_execution_context.txt4
-rw-r--r--test/prism/errors/pre_execution_missing_brace.txt3
-rw-r--r--test/prism/errors/range_and_bin_op.txt5
-rw-r--r--test/prism/errors/range_and_bin_op_2.txt5
-rw-r--r--test/prism/errors/range_and_bin_op_3.txt3
-rw-r--r--test/prism/errors/range_and_bin_op_4.txt5
-rw-r--r--test/prism/errors/range_and_bin_op_5.txt6
-rw-r--r--test/prism/errors/range_and_bin_op_6.txt3
-rw-r--r--test/prism/errors/range_and_bin_op_7.txt3
-rw-r--r--test/prism/errors/range_and_bin_op_8.txt4
-rw-r--r--test/prism/errors/range_doubled.txt3
-rw-r--r--test/prism/errors/rational_number_with_exponential_portion.txt4
-rw-r--r--test/prism/errors/regexp_unicode_too_short.txt4
-rw-r--r--test/prism/errors/regular_expression_with_unknown_regexp_options.txt3
-rw-r--r--test/prism/errors/repeated_parameter_name_in_destructured_params.txt3
-rw-r--r--test/prism/errors/rescue_pattern.txt4
-rw-r--r--test/prism/errors/rest_keywords_parameters_before_required_parameters.txt4
-rw-r--r--test/prism/errors/return_1.txt3
-rw-r--r--test/prism/errors/return_1_2_3.txt7
-rw-r--r--test/prism/errors/returning_to_optional_parameters_multiple_times.txt4
-rw-r--r--test/prism/errors/semicolon_after_inheritance_operator.txt3
-rw-r--r--test/prism/errors/setter_method_cannot_be_defined_in_an_endless_method_definition.txt6
-rw-r--r--test/prism/errors/shadow_args_in_block.txt3
-rw-r--r--test/prism/errors/shadow_args_in_lambda.txt5
-rw-r--r--test/prism/errors/singleton_class_delimiter.txt3
-rw-r--r--test/prism/errors/singleton_method_for_literals.txt37
-rw-r--r--test/prism/errors/splat_argument_after_keyword_argument.txt3
-rw-r--r--test/prism/errors/statement_at_non_statement.txt9
-rw-r--r--test/prism/errors/statement_operators.txt25
-rw-r--r--test/prism/errors/switching_to_named_arguments_twice.txt5
-rw-r--r--test/prism/errors/switching_to_optional_arguments_twice.txt5
-rw-r--r--test/prism/errors/symbol_in_hash.txt3
-rw-r--r--test/prism/errors/symbol_in_keyword_parameter.txt3
-rw-r--r--test/prism/errors/targeting_numbered_parameter.txt3
-rw-r--r--test/prism/errors/top_level_constant_starting_with_downcased_identifier.txt4
-rw-r--r--test/prism/errors/top_level_constant_with_downcased_identifier.txt4
-rw-r--r--test/prism/errors/trailing_comma_after_block.txt3
-rw-r--r--test/prism/errors/trailing_comma_in_calls.txt3
-rw-r--r--test/prism/errors/unexpected_block.txt3
-rw-r--r--test/prism/errors/unterminated_W_list.txt3
-rw-r--r--test/prism/errors/unterminated_argument_expression.txt5
-rw-r--r--test/prism/errors/unterminated_begin.txt4
-rw-r--r--test/prism/errors/unterminated_begin_upcase.txt4
-rw-r--r--test/prism/errors/unterminated_block.txt4
-rw-r--r--test/prism/errors/unterminated_block_do_end.txt4
-rw-r--r--test/prism/errors/unterminated_class.txt4
-rw-r--r--test/prism/errors/unterminated_def.txt5
-rw-r--r--test/prism/errors/unterminated_embdoc.txt3
-rw-r--r--test/prism/errors/unterminated_embdoc_2.txt3
-rw-r--r--test/prism/errors/unterminated_empty_string.txt3
-rw-r--r--test/prism/errors/unterminated_end_upcase.txt4
-rw-r--r--test/prism/errors/unterminated_for.txt5
-rw-r--r--test/prism/errors/unterminated_global_variable.txt3
-rw-r--r--test/prism/errors/unterminated_global_variable_2.txt3
-rw-r--r--test/prism/errors/unterminated_heredoc_and_embexpr.txt11
-rw-r--r--test/prism/errors/unterminated_heredoc_and_embexpr_2.txt9
-rw-r--r--test/prism/errors/unterminated_i_list.txt3
-rw-r--r--test/prism/errors/unterminated_if.txt5
-rw-r--r--test/prism/errors/unterminated_if_else.txt5
-rw-r--r--test/prism/errors/unterminated_interpolated_string.txt3
-rw-r--r--test/prism/errors/unterminated_interpolated_symbol.txt3
-rw-r--r--test/prism/errors/unterminated_lambda_brace.txt4
-rw-r--r--test/prism/errors/unterminated_method_parameters.txt3
-rw-r--r--test/prism/errors/unterminated_module.txt4
-rw-r--r--test/prism/errors/unterminated_parenthesized_expression.txt4
-rw-r--r--test/prism/errors/unterminated_pattern_bracket.txt7
-rw-r--r--test/prism/errors/unterminated_pattern_paren.txt7
-rw-r--r--test/prism/errors/unterminated_regular_expression.txt3
-rw-r--r--test/prism/errors/unterminated_regular_expression_with_heredoc.txt4
-rw-r--r--test/prism/errors/unterminated_s_symbol.txt3
-rw-r--r--test/prism/errors/unterminated_string.txt3
-rw-r--r--test/prism/errors/unterminated_unicode_brackets_should_be_a_syntax_error.txt3
-rw-r--r--test/prism/errors/unterminated_until.txt5
-rw-r--r--test/prism/errors/unterminated_xstring.txt3
-rw-r--r--test/prism/errors/void_value_expression_in_arguments.txt17
-rw-r--r--test/prism/errors/void_value_expression_in_array.txt15
-rw-r--r--test/prism/errors/void_value_expression_in_assignment.txt9
-rw-r--r--test/prism/errors/void_value_expression_in_begin_statement.txt19
-rw-r--r--test/prism/errors/void_value_expression_in_binary_call.txt11
-rw-r--r--test/prism/errors/void_value_expression_in_call.txt11
-rw-r--r--test/prism/errors/void_value_expression_in_constant_path.txt5
-rw-r--r--test/prism/errors/void_value_expression_in_def.txt10
-rw-r--r--test/prism/errors/void_value_expression_in_expression.txt19
-rw-r--r--test/prism/errors/void_value_expression_in_hash.txt9
-rw-r--r--test/prism/errors/void_value_expression_in_modifier.txt13
-rw-r--r--test/prism/errors/void_value_expression_in_statement.txt26
-rw-r--r--test/prism/errors/void_value_expression_in_unary_call.txt5
-rw-r--r--test/prism/errors/while_endless_method.txt5
-rw-r--r--test/prism/errors/writing_numbered_parameter.txt3
-rw-r--r--test/prism/errors/xstring_concat.txt5
-rw-r--r--test/prism/errors_test.rb135
-rw-r--r--test/prism/fixtures/3.3-3.3/block_args_in_array_assignment.txt1
-rw-r--r--test/prism/fixtures/3.3-3.3/it.txt5
-rw-r--r--test/prism/fixtures/3.3-3.3/it_indirect_writes.txt23
-rw-r--r--test/prism/fixtures/3.3-3.3/it_read_and_assignment.txt1
-rw-r--r--test/prism/fixtures/3.3-3.3/it_with_ordinary_parameter.txt1
-rw-r--r--test/prism/fixtures/3.3-3.3/keyword_args_in_array_assignment.txt1
-rw-r--r--test/prism/fixtures/3.3-3.3/return_in_sclass.txt1
-rw-r--r--test/prism/fixtures/3.3-4.0/end_block_exit.txt11
-rw-r--r--test/prism/fixtures/3.3-4.0/void_value.txt29
-rw-r--r--test/prism/fixtures/3.4/circular_parameters.txt4
-rw-r--r--test/prism/fixtures/3.4/it.txt5
-rw-r--r--test/prism/fixtures/3.4/it_indirect_writes.txt23
-rw-r--r--test/prism/fixtures/3.4/it_read_and_assignment.txt1
-rw-r--r--test/prism/fixtures/4.0/endless_methods_command_call.txt11
-rw-r--r--test/prism/fixtures/4.0/leading_logical.txt16
-rw-r--r--test/prism/fixtures/4.1/noblock.txt4
-rw-r--r--test/prism/fixtures/4.1/trailing_comma_after_method_arguments.txt15
-rw-r--r--test/prism/fixtures/4.1/void_value.txt7
-rw-r--r--test/prism/fixtures/__END__.txt3
-rw-r--r--test/prism/fixtures/alias.txt23
-rw-r--r--test/prism/fixtures/and_or_with_suffix.txt17
-rw-r--r--test/prism/fixtures/arithmetic.txt13
-rw-r--r--test/prism/fixtures/arrays.txt122
-rw-r--r--test/prism/fixtures/begin_ensure.txt21
-rw-r--r--test/prism/fixtures/begin_rescue.txt85
-rw-r--r--test/prism/fixtures/blocks.txt62
-rw-r--r--test/prism/fixtures/bom_leading_space.txt1
-rw-r--r--test/prism/fixtures/bom_spaces.txt1
-rw-r--r--test/prism/fixtures/boolean_operators.txt5
-rw-r--r--test/prism/fixtures/booleans.txt3
-rw-r--r--test/prism/fixtures/break.txt33
-rw-r--r--test/prism/fixtures/case.txt55
-rw-r--r--test/prism/fixtures/case_in_hash_key.txt6
-rw-r--r--test/prism/fixtures/case_in_in.txt4
-rw-r--r--test/prism/fixtures/character_literal.txt2
-rw-r--r--test/prism/fixtures/classes.txt35
-rw-r--r--test/prism/fixtures/command_method_call.txt41
-rw-r--r--test/prism/fixtures/command_method_call_2.txt1
-rw-r--r--test/prism/fixtures/command_method_call_3.txt19
-rw-r--r--test/prism/fixtures/comment_single.txt1
-rw-r--r--test/prism/fixtures/comments.txt24
-rw-r--r--test/prism/fixtures/constants.txt184
-rw-r--r--test/prism/fixtures/dash_heredocs.txt63
-rw-r--r--test/prism/fixtures/defined.txt19
-rw-r--r--test/prism/fixtures/dos_endings.txt20
-rw-r--r--test/prism/fixtures/dstring.txt42
-rw-r--r--test/prism/fixtures/dsym_str.txt5
-rw-r--r--test/prism/fixtures/embdoc_no_newline_at_end.txt2
-rw-r--r--test/prism/fixtures/emoji_method_calls.txt1
-rw-r--r--test/prism/fixtures/encoding_binary.txt9
-rw-r--r--test/prism/fixtures/encoding_euc_jp.txt6
-rw-r--r--test/prism/fixtures/endless_method_as_default_arg.txt11
-rw-r--r--test/prism/fixtures/endless_methods.txt11
-rw-r--r--test/prism/fixtures/endless_range_in_conditional.txt3
-rw-r--r--test/prism/fixtures/escaped_newline_with_trailing_content.txt2
-rw-r--r--test/prism/fixtures/for.txt19
-rw-r--r--test/prism/fixtures/global_variables.txt93
-rw-r--r--test/prism/fixtures/hashes.txt28
-rw-r--r--test/prism/fixtures/heredoc.txt2
-rw-r--r--test/prism/fixtures/heredoc_dedent_line_continuation.txt5
-rw-r--r--test/prism/fixtures/heredoc_percent_q_newline_delimiter.txt22
-rw-r--r--test/prism/fixtures/heredoc_with_carriage_returns.txt2
-rw-r--r--test/prism/fixtures/heredoc_with_comment.txt3
-rw-r--r--test/prism/fixtures/heredoc_with_escaped_newline_at_start.txt7
-rw-r--r--test/prism/fixtures/heredoc_with_trailing_newline.txt2
-rw-r--r--test/prism/fixtures/heredocs_leading_whitespace.txt29
-rw-r--r--test/prism/fixtures/heredocs_nested.txt22
-rw-r--r--test/prism/fixtures/heredocs_with_fake_newlines.txt55
-rw-r--r--test/prism/fixtures/heredocs_with_ignored_newlines.txt14
-rw-r--r--test/prism/fixtures/heredocs_with_ignored_newlines_and_non_empty.txt4
-rw-r--r--test/prism/fixtures/if.txt42
-rw-r--r--test/prism/fixtures/indented_file_end.txt4
-rw-r--r--test/prism/fixtures/integer_operations.txt63
-rw-r--r--test/prism/fixtures/it_assignment.txt1
-rw-r--r--test/prism/fixtures/keyword_method_names.txt20
-rw-r--r--test/prism/fixtures/keywords.txt11
-rw-r--r--test/prism/fixtures/lambda.txt27
-rw-r--r--test/prism/fixtures/method_calls.txt156
-rw-r--r--test/prism/fixtures/methods.txt190
-rw-r--r--test/prism/fixtures/modules.txt18
-rw-r--r--test/prism/fixtures/multi_write.txt4
-rw-r--r--test/prism/fixtures/newline_terminated.txtbin0 -> 212 bytes
-rw-r--r--test/prism/fixtures/next.txt28
-rw-r--r--test/prism/fixtures/nils.txt13
-rw-r--r--test/prism/fixtures/non_alphanumeric_methods.txt105
-rw-r--r--test/prism/fixtures/non_void_value.txt31
-rw-r--r--test/prism/fixtures/not.txt37
-rw-r--r--test/prism/fixtures/numbers.txt67
-rw-r--r--test/prism/fixtures/patterns.txt224
-rw-r--r--test/prism/fixtures/procs.txt27
-rw-r--r--test/prism/fixtures/range_begin_open_exclusive.txt1
-rw-r--r--test/prism/fixtures/range_begin_open_inclusive.txt1
-rw-r--r--test/prism/fixtures/range_beginless.txt5
-rw-r--r--test/prism/fixtures/range_end_open_exclusive.txt1
-rw-r--r--test/prism/fixtures/range_end_open_inclusive.txt1
-rw-r--r--test/prism/fixtures/ranges.txt51
-rw-r--r--test/prism/fixtures/regex.txt58
-rw-r--r--test/prism/fixtures/regex_char_width.txt3
-rw-r--r--test/prism/fixtures/regex_escape_encoding.txt3
-rw-r--r--test/prism/fixtures/regex_with_fake_newlines.txt41
-rw-r--r--test/prism/fixtures/repeat_parameters.txt38
-rw-r--r--test/prism/fixtures/rescue.txt39
-rw-r--r--test/prism/fixtures/rescue_modifier.txt7
-rw-r--r--test/prism/fixtures/return.txt27
-rw-r--r--test/prism/fixtures/seattlerb/BEGIN.txt1
-rw-r--r--test/prism/fixtures/seattlerb/README.rdoc113
-rw-r--r--test/prism/fixtures/seattlerb/TestRubyParserShared.txt92
-rw-r--r--test/prism/fixtures/seattlerb/__ENCODING__.txt1
-rw-r--r--test/prism/fixtures/seattlerb/alias_gvar_backref.txt1
-rw-r--r--test/prism/fixtures/seattlerb/alias_resword.txt1
-rw-r--r--test/prism/fixtures/seattlerb/and_multi.txt3
-rw-r--r--test/prism/fixtures/seattlerb/aref_args_assocs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/aref_args_lit_assocs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/args_kw_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/array_line_breaks.txt4
-rw-r--r--test/prism/fixtures/seattlerb/array_lits_trailing_calls.txt3
-rw-r--r--test/prism/fixtures/seattlerb/assoc__bare.txt1
-rw-r--r--test/prism/fixtures/seattlerb/assoc_label.txt1
-rw-r--r--test/prism/fixtures/seattlerb/attr_asgn_colon_id.txt1
-rw-r--r--test/prism/fixtures/seattlerb/attrasgn_array_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/attrasgn_array_lhs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/attrasgn_primary_dot_constant.txt1
-rw-r--r--test/prism/fixtures/seattlerb/backticks_interpolation_line.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bang_eq.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bdot2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bdot3.txt3
-rw-r--r--test/prism/fixtures/seattlerb/begin_ensure_no_bodies.txt3
-rw-r--r--test/prism/fixtures/seattlerb/begin_rescue_else_ensure_bodies.txt9
-rw-r--r--test/prism/fixtures/seattlerb/begin_rescue_else_ensure_no_bodies.txt9
-rw-r--r--test/prism/fixtures/seattlerb/begin_rescue_ensure_no_bodies.txt4
-rw-r--r--test/prism/fixtures/seattlerb/block_arg__bare.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_opt_arg_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_opt_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_opt_splat_arg_block_omfg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_optional.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_scope.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_scope2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_kwargs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_no_kwargs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_opt1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_opt2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_opt2_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_opt3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_defn_call_block_call.txt4
-rw-r--r--test/prism/fixtures/seattlerb/block_call_dot_op2_brace_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_dot_op2_cmd_args_do_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_operation_colon.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_operation_dot.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_paren_call_block_call.txt2
-rw-r--r--test/prism/fixtures/seattlerb/block_command_operation_colon.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_command_operation_dot.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_decomp_anon_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_decomp_arg_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_decomp_arg_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_decomp_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_kw.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_kw__required.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_kwarg_lvar.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_kwarg_lvar_multiple.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_opt_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_opt_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_opt_splat_arg_block_omfg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_optarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_paren_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_reg_optarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_return.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_scope.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_splat_reg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug169.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug179.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug190.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug191.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bug202.txt2
-rw-r--r--test/prism/fixtures/seattlerb/bug236.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bug290.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bug_187.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bug_215.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_249.txt4
-rw-r--r--test/prism/fixtures/seattlerb/bug_and.txt4
-rw-r--r--test/prism/fixtures/seattlerb/bug_args__19.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_args_masgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_args_masgn2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_args_masgn_outer_parens__19.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_call_arglist_parens.txt11
-rw-r--r--test/prism/fixtures/seattlerb/bug_case_when_regexp.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_cond_pct.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_hash_args.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_hash_args_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_hash_interp_array.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_masgn_right.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_not_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_op_asgn_rescue.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_and.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_arg_assoc.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_arg_assoc_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_arg_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_args_assoc_quoted.txt5
-rw-r--r--test/prism/fixtures/seattlerb/call_args_assoc_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_args_command.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_array_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_array_block_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_array_lambda_block_call.txt2
-rw-r--r--test/prism/fixtures/seattlerb/call_array_lit_inline_hash.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_assoc.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_assoc_new.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_assoc_new_if_multiline.txt5
-rw-r--r--test/prism/fixtures/seattlerb/call_assoc_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_bang_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_bang_squiggle.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_begin_call_block_call.txt3
-rw-r--r--test/prism/fixtures/seattlerb/call_block_arg_named.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_carat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_colon2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_colon_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_div.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_dot_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_env.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_eq3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_gt.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_leading_dots.txt3
-rw-r--r--test/prism/fixtures/seattlerb/call_leading_dots_comment.txt4
-rw-r--r--test/prism/fixtures/seattlerb/call_lt.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_lte.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_not.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_pipe.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_rshift.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_self_brackets.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_spaceship.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_stabby_do_end_with_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_stabby_with_braces_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_star.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_star2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_trailing_dots.txt3
-rw-r--r--test/prism/fixtures/seattlerb/call_unary_bang.txt1
-rw-r--r--test/prism/fixtures/seattlerb/case_in.txt111
-rw-r--r--test/prism/fixtures/seattlerb/case_in_31.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_37.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_42.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_42_2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_47.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_67.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_86.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_86_2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_array_pat_const.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_array_pat_const2.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_array_pat_paren_assign.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_const.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_else.txt7
-rw-r--r--test/prism/fixtures/seattlerb/case_in_find.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_find_array.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat.txt5
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_assign.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_paren_assign.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_paren_true.txt5
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_rest.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_rest_solo.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_if_unless_post_mod.txt6
-rw-r--r--test/prism/fixtures/seattlerb/case_in_multiple.txt6
-rw-r--r--test/prism/fixtures/seattlerb/case_in_or.txt5
-rw-r--r--test/prism/fixtures/seattlerb/class_comments.txt9
-rw-r--r--test/prism/fixtures/seattlerb/cond_unary_minus.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_2_op_asgn_or2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_3_op_asgn_or.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_op_asgn_and1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_op_asgn_and2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_op_asgn_or.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defined_eh_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_arg_asplat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_arg_forward_args.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_args_forward_args.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_comments.txt5
-rw-r--r--test/prism/fixtures/seattlerb/defn_endless_command.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_endless_command_rescue.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_forward_args.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_forward_args__no_parens.txt3
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_env.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_kwarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_kwsplat_anon.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_lvar.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_no_parens.txt2
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_val.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_no_kwargs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner_eq2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner_noargs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner_noargs_parentheses.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner_rescue.txt13
-rw-r--r--test/prism/fixtures/seattlerb/defn_opt_last_arg.txt2
-rw-r--r--test/prism/fixtures/seattlerb/defn_opt_reg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_opt_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_powarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_reg_opt_reg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_unary_not.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defns_reserved.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_as_arg_with_do_block_inside.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_comments.txt5
-rw-r--r--test/prism/fixtures/seattlerb/defs_endless_command.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_endless_command_rescue.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_kwarg.txt2
-rw-r--r--test/prism/fixtures/seattlerb/defs_oneliner.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_oneliner_eq2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/defs_oneliner_rescue.txt13
-rw-r--r--test/prism/fixtures/seattlerb/difficult0_.txt4
-rw-r--r--test/prism/fixtures/seattlerb/difficult1_line_numbers.txt13
-rw-r--r--test/prism/fixtures/seattlerb/difficult1_line_numbers2.txt8
-rw-r--r--test/prism/fixtures/seattlerb/difficult2_.txt2
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_4.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_5.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__10.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__11.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__12.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__6.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__7.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__8.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__9.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult4__leading_dots.txt2
-rw-r--r--test/prism/fixtures/seattlerb/difficult4__leading_dots2.txt2
-rw-r--r--test/prism/fixtures/seattlerb/difficult6_.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult6__7.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult6__8.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult7_.txt5
-rw-r--r--test/prism/fixtures/seattlerb/do_bug.txt4
-rw-r--r--test/prism/fixtures/seattlerb/do_lambda.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dot2_nil__26.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dot3_nil__26.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dstr_evstr.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dstr_evstr_empty_end.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dstr_lex_state.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dstr_str.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dsym_esc_to_sym.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dsym_to_sym.txt3
-rw-r--r--test/prism/fixtures/seattlerb/eq_begin_line_numbers.txt6
-rw-r--r--test/prism/fixtures/seattlerb/eq_begin_why_wont_people_use_their_spacebar.txt3
-rw-r--r--test/prism/fixtures/seattlerb/evstr_evstr.txt1
-rw-r--r--test/prism/fixtures/seattlerb/evstr_str.txt1
-rw-r--r--test/prism/fixtures/seattlerb/expr_not_bang.txt1
-rw-r--r--test/prism/fixtures/seattlerb/f_kw.txt1
-rw-r--r--test/prism/fixtures/seattlerb/f_kw__required.txt1
-rw-r--r--test/prism/fixtures/seattlerb/flip2_env_lvar.txt1
-rw-r--r--test/prism/fixtures/seattlerb/float_with_if_modifier.txt1
-rw-r--r--test/prism/fixtures/seattlerb/heredoc__backslash_dos_format.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_backslash_nl.txt8
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_bad_hex_escape.txt3
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_bad_oct_escape.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_comma_arg.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_lineno.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_nested.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_blank_line_plus_interpolation.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_blank_lines.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_empty.txt2
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_interp.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_no_indent.txt3
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_tabs.txt6
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_tabs_extra.txt6
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_visually_blank_lines.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_trailing_slash_continued_call.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_unicode.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_carriage_return_escapes.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_carriage_return_escapes_windows.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_horrible_mix.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_returns.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_returns_windows.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes_windows.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_not_global_interpolation.txt3
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_only_carriage_returns.txt6
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_only_carriage_returns_windows.txt6
-rw-r--r--test/prism/fixtures/seattlerb/if_elsif.txt1
-rw-r--r--test/prism/fixtures/seattlerb/if_symbol.txt1
-rw-r--r--test/prism/fixtures/seattlerb/in_expr_no_case.txt1
-rw-r--r--test/prism/fixtures/seattlerb/index_0.txt1
-rw-r--r--test/prism/fixtures/seattlerb/index_0_opasgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/integer_with_if_modifier.txt1
-rw-r--r--test/prism/fixtures/seattlerb/interpolated_symbol_array_line_breaks.txt5
-rw-r--r--test/prism/fixtures/seattlerb/interpolated_word_array_line_breaks.txt5
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_10_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_10_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_11_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_11_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_2__19.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_4.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_5.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_6.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_7_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_7_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_8_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_8_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_9_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_9_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_kwarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_kwarg_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/label_vs_string.txt2
-rw-r--r--test/prism/fixtures/seattlerb/lambda_do_vs_brace.txt7
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_arg_rescue_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_call_bracket_rescue_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_call_nobracket_rescue_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_command.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_env.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_ivar_env.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_lasgn_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_middle_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/magic_encoding_comment.txt4
-rw-r--r--test/prism/fixtures/seattlerb/masgn_anon_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_arg_colon_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_arg_ident.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_arg_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_colon2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_colon3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_double_paren.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_lhs_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_paren.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_splat_arg_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_star.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_var_star_var.txt1
-rw-r--r--test/prism/fixtures/seattlerb/messy_op_asgn_lineno.txt1
-rw-r--r--test/prism/fixtures/seattlerb/method_call_assoc_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/method_call_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_back_anonsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_back_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_front_anonsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_front_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_keyword.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_mid_anonsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_mid_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_rescue.txt1
-rw-r--r--test/prism/fixtures/seattlerb/module_comments.txt10
-rw-r--r--test/prism/fixtures/seattlerb/multiline_hash_declaration.txt8
-rw-r--r--test/prism/fixtures/seattlerb/non_interpolated_symbol_array_line_breaks.txt5
-rw-r--r--test/prism/fixtures/seattlerb/non_interpolated_word_array_line_breaks.txt5
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_dot_ident_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_index_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_primary_colon_const_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_primary_colon_identifier1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_primary_colon_identifier_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_val_dot_ident_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_def_special_name.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_if_not_canonical.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_if_not_noncanonical.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_block.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_block_inline_comment.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_block_inline_comment_leading_newlines.txt7
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_block_inline_multiline_comment.txt4
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_call_ivar_arg_no_parens_line_break.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_call_ivar_line_break_paren.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_call_no_args.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_defn_complex.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_defn_no_parens.txt6
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_defn_no_parens_args.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dot2.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dot2_open.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dot3.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dot3_open.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dstr_escaped_newline.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dstr_soft_newline.txt4
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_evstr_after_break.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_hash_lit.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_heredoc.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_heredoc_evstr.txt4
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_heredoc_hardnewline.txt7
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_heredoc_regexp_chars.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_iter_call_no_parens.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_iter_call_parens.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_multiline_str.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_multiline_str_literal_n.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_newlines.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_op_asgn.txt4
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_postexe.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_preexe.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_rescue.txt8
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_return.txt6
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_str_with_newline_escape.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_to_ary.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_trailing_newlines.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_opt_call_args_assocs_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_opt_call_args_lit_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_019.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_044.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_051.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_058.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_058_2.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_069.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_076.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_until_not_canonical.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_until_not_noncanonical.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_while_not_canonical.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_while_not_noncanonical.txt3
-rw-r--r--test/prism/fixtures/seattlerb/pctW_lineno.txt5
-rw-r--r--test/prism/fixtures/seattlerb/pct_Q_backslash_nl.txt2
-rw-r--r--test/prism/fixtures/seattlerb/pct_nl.txt3
-rw-r--r--test/prism/fixtures/seattlerb/pct_w_heredoc_interp_nested.txt4
-rw-r--r--test/prism/fixtures/seattlerb/pipe_semicolon.txt1
-rw-r--r--test/prism/fixtures/seattlerb/pipe_space.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qWords_space.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qsymbols.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qsymbols_empty.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qsymbols_empty_space.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qsymbols_interp.txt1
-rw-r--r--test/prism/fixtures/seattlerb/quoted_symbol_hash_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/quoted_symbol_keys.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qw_escape.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qw_escape_term.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qwords_empty.txt1
-rw-r--r--test/prism/fixtures/seattlerb/read_escape_unicode_curlies.txt1
-rw-r--r--test/prism/fixtures/seattlerb/read_escape_unicode_h4.txt1
-rw-r--r--test/prism/fixtures/seattlerb/regexp.txt9
-rw-r--r--test/prism/fixtures/seattlerb/regexp_esc_C_slash.txt1
-rw-r--r--test/prism/fixtures/seattlerb/regexp_esc_u.txt1
-rw-r--r--test/prism/fixtures/seattlerb/regexp_escape_extended.txt1
-rw-r--r--test/prism/fixtures/seattlerb/regexp_unicode_curlies.txt3
-rw-r--r--test/prism/fixtures/seattlerb/required_kwarg_no_value.txt2
-rw-r--r--test/prism/fixtures/seattlerb/rescue_do_end_ensure_result.txt5
-rw-r--r--test/prism/fixtures/seattlerb/rescue_do_end_no_raise.txt9
-rw-r--r--test/prism/fixtures/seattlerb/rescue_do_end_raised.txt5
-rw-r--r--test/prism/fixtures/seattlerb/rescue_do_end_rescued.txt9
-rw-r--r--test/prism/fixtures/seattlerb/rescue_in_block.txt4
-rw-r--r--test/prism/fixtures/seattlerb/rescue_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/return_call_assocs.txt11
-rw-r--r--test/prism/fixtures/seattlerb/rhs_asgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/ruby21_numbers.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_attrasgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_attrasgn_constant.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_after_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_dot_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_operator.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_rhs_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/safe_calls.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_op_asgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_op_asgn2.txt2
-rw-r--r--test/prism/fixtures/seattlerb/slashy_newlines_within_string.txt7
-rw-r--r--test/prism/fixtures/seattlerb/stabby_arg_no_paren.txt1
-rw-r--r--test/prism/fixtures/seattlerb/stabby_arg_opt_splat_arg_block_omfg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/stabby_block_iter_call.txt4
-rw-r--r--test/prism/fixtures/seattlerb/stabby_block_iter_call_no_target_with_arg.txt4
-rw-r--r--test/prism/fixtures/seattlerb/stabby_block_kw.txt1
-rw-r--r--test/prism/fixtures/seattlerb/stabby_block_kw__required.txt1
-rw-r--r--test/prism/fixtures/seattlerb/stabby_proc_scope.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_backslashes.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_double_double_escaped_newline.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_double_escaped_newline.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_double_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/str_evstr.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_evstr_escape.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_heredoc_interp.txt5
-rw-r--r--test/prism/fixtures/seattlerb/str_interp_ternary_or_label.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_lit_concat_bad_encodings.txt2
-rw-r--r--test/prism/fixtures/seattlerb/str_newline_hash_line_number.txt2
-rw-r--r--test/prism/fixtures/seattlerb/str_pct_Q_nested.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_pct_nested_nested.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_pct_q.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_single_double_escaped_newline.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_single_escaped_newline.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_single_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/str_str.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_str_str.txt1
-rw-r--r--test/prism/fixtures/seattlerb/super_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbol_empty.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbol_list.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbols.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbols_empty.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbols_empty_space.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbols_interp.txt1
-rw-r--r--test/prism/fixtures/seattlerb/thingy.txt3
-rw-r--r--test/prism/fixtures/seattlerb/uminus_float.txt1
-rw-r--r--test/prism/fixtures/seattlerb/unary_minus.txt1
-rw-r--r--test/prism/fixtures/seattlerb/unary_plus.txt1
-rw-r--r--test/prism/fixtures/seattlerb/unary_plus_on_literal.txt1
-rw-r--r--test/prism/fixtures/seattlerb/unary_tilde.txt1
-rw-r--r--test/prism/fixtures/seattlerb/utf8_bom.txt3
-rw-r--r--test/prism/fixtures/seattlerb/when_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/words_interp.txt1
-rw-r--r--test/prism/fixtures/single_method_call_with_bang.txt1
-rw-r--r--test/prism/fixtures/single_quote_heredocs.txt3
-rw-r--r--test/prism/fixtures/spanning_heredoc.txt63
-rw-r--r--test/prism/fixtures/spanning_heredoc_newlines.txt23
-rw-r--r--test/prism/fixtures/string_concatination_frozen_false.txt5
-rw-r--r--test/prism/fixtures/string_concatination_frozen_true.txt5
-rw-r--r--test/prism/fixtures/strings.txt185
-rw-r--r--test/prism/fixtures/super.txt17
-rw-r--r--test/prism/fixtures/symbols.txt104
-rw-r--r--test/prism/fixtures/ternary_operator.txt15
-rw-r--r--test/prism/fixtures/tilde_heredocs.txt97
-rw-r--r--test/prism/fixtures/unary_method_calls.txt8
-rw-r--r--test/prism/fixtures/undef.txt17
-rw-r--r--test/prism/fixtures/unescaping.txt9
-rw-r--r--test/prism/fixtures/unless.txt14
-rw-r--r--test/prism/fixtures/unparser/LICENSE20
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/alias.txt2
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/assignment.txt53
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/block.txt96
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/case.txt37
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/class.txt35
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/def.txt134
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/defined.txt3
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/defs.txt40
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/dstr.txt37
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/empty.txt0
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/empty_begin.txt1
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/flipflop.txt10
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/for.txt12
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/hookexe.txt7
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/if.txt36
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/kwbegin.txt80
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/lambda.txt13
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/literal.txt91
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/module.txt16
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/opasgn.txt24
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/pattern.txt41
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/pragma.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/range.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/rescue.txt3
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/send.txt84
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/since/27.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/since/30.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/since/31.txt7
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/since/32.txt11
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/singletons.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/super.txt21
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/unary.txt9
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/undef.txt2
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/variables.txt10
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/while.txt73
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/and.txt8
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/block.txt26
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/def.txt7
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/dstr.txt127
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/kwbegin.txt42
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/literal.txt14
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/opasgn.txt1
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/send.txt6
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/undef.txt2
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/while.txt25
-rw-r--r--test/prism/fixtures/until.txt13
-rw-r--r--test/prism/fixtures/variables.txt49
-rw-r--r--test/prism/fixtures/while.txt23
-rw-r--r--test/prism/fixtures/whitequark/LICENSE26
-rw-r--r--test/prism/fixtures/whitequark/__ENCODING__.txt1
-rw-r--r--test/prism/fixtures/whitequark/__ENCODING___legacy_.txt1
-rw-r--r--test/prism/fixtures/whitequark/alias.txt1
-rw-r--r--test/prism/fixtures/whitequark/alias_gvar.txt3
-rw-r--r--test/prism/fixtures/whitequark/ambiuous_quoted_label_in_ternary_operator.txt1
-rw-r--r--test/prism/fixtures/whitequark/and.txt3
-rw-r--r--test/prism/fixtures/whitequark/and_asgn.txt3
-rw-r--r--test/prism/fixtures/whitequark/and_or_masgn.txt3
-rw-r--r--test/prism/fixtures/whitequark/anonymous_blockarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/arg.txt3
-rw-r--r--test/prism/fixtures/whitequark/arg_combinations.txt29
-rw-r--r--test/prism/fixtures/whitequark/arg_duplicate_ignored.txt3
-rw-r--r--test/prism/fixtures/whitequark/arg_label.txt6
-rw-r--r--test/prism/fixtures/whitequark/arg_scope.txt1
-rw-r--r--test/prism/fixtures/whitequark/args.txt63
-rw-r--r--test/prism/fixtures/whitequark/args_args_assocs.txt3
-rw-r--r--test/prism/fixtures/whitequark/args_args_assocs_comma.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_args_comma.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_args_star.txt3
-rw-r--r--test/prism/fixtures/whitequark/args_assocs_comma.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_block_pass.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_star.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_assocs.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_plain.txt1
-rw-r--r--test/prism/fixtures/whitequark/array_splat.txt5
-rw-r--r--test/prism/fixtures/whitequark/array_symbols.txt1
-rw-r--r--test/prism/fixtures/whitequark/array_symbols_empty.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_symbols_interp.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_words.txt1
-rw-r--r--test/prism/fixtures/whitequark/array_words_empty.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_words_interp.txt3
-rw-r--r--test/prism/fixtures/whitequark/asgn_cmd.txt3
-rw-r--r--test/prism/fixtures/whitequark/asgn_mrhs.txt5
-rw-r--r--test/prism/fixtures/whitequark/back_ref.txt1
-rw-r--r--test/prism/fixtures/whitequark/bang.txt1
-rw-r--r--test/prism/fixtures/whitequark/bang_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/begin_cmdarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/beginless_erange_after_newline.txt2
-rw-r--r--test/prism/fixtures/whitequark/beginless_irange_after_newline.txt2
-rw-r--r--test/prism/fixtures/whitequark/beginless_range.txt3
-rw-r--r--test/prism/fixtures/whitequark/block_arg_combinations.txt57
-rw-r--r--test/prism/fixtures/whitequark/block_kwarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/block_kwarg_combinations.txt5
-rw-r--r--test/prism/fixtures/whitequark/blockarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/blockargs.txt71
-rw-r--r--test/prism/fixtures/whitequark/bug_435.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_447.txt3
-rw-r--r--test/prism/fixtures/whitequark/bug_452.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_466.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_473.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_480.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_481.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_ascii_8bit_in_literal.txt2
-rw-r--r--test/prism/fixtures/whitequark/bug_cmd_string_lookahead.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_cmdarg.txt5
-rw-r--r--test/prism/fixtures/whitequark/bug_def_no_paren_eql_begin.txt4
-rw-r--r--test/prism/fixtures/whitequark/bug_do_block_in_call_args.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_do_block_in_cmdarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_do_block_in_hash_brace.txt9
-rw-r--r--test/prism/fixtures/whitequark/bug_heredoc_do.txt3
-rw-r--r--test/prism/fixtures/whitequark/bug_interp_single.txt3
-rw-r--r--test/prism/fixtures/whitequark/bug_lambda_leakage.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_regex_verification.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_rescue_empty_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_while_not_parens_do.txt1
-rw-r--r--test/prism/fixtures/whitequark/case_cond.txt1
-rw-r--r--test/prism/fixtures/whitequark/case_cond_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/case_expr.txt1
-rw-r--r--test/prism/fixtures/whitequark/case_expr_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/casgn_scoped.txt1
-rw-r--r--test/prism/fixtures/whitequark/casgn_toplevel.txt1
-rw-r--r--test/prism/fixtures/whitequark/casgn_unscoped.txt1
-rw-r--r--test/prism/fixtures/whitequark/character.txt1
-rw-r--r--test/prism/fixtures/whitequark/class.txt3
-rw-r--r--test/prism/fixtures/whitequark/class_super.txt1
-rw-r--r--test/prism/fixtures/whitequark/class_super_label.txt1
-rw-r--r--test/prism/fixtures/whitequark/comments_before_leading_dot__27.txt19
-rw-r--r--test/prism/fixtures/whitequark/complex.txt7
-rw-r--r--test/prism/fixtures/whitequark/cond_begin.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_begin_masgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_eflipflop.txt3
-rw-r--r--test/prism/fixtures/whitequark/cond_eflipflop_with_beginless_range.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_eflipflop_with_endless_range.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_iflipflop.txt3
-rw-r--r--test/prism/fixtures/whitequark/cond_iflipflop_with_beginless_range.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_iflipflop_with_endless_range.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_match_current_line.txt3
-rw-r--r--test/prism/fixtures/whitequark/const_op_asgn.txt9
-rw-r--r--test/prism/fixtures/whitequark/const_scoped.txt1
-rw-r--r--test/prism/fixtures/whitequark/const_toplevel.txt1
-rw-r--r--test/prism/fixtures/whitequark/const_unscoped.txt1
-rw-r--r--test/prism/fixtures/whitequark/cpath.txt3
-rw-r--r--test/prism/fixtures/whitequark/cvar.txt1
-rw-r--r--test/prism/fixtures/whitequark/cvasgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/dedenting_heredoc.txt75
-rw-r--r--test/prism/fixtures/whitequark/dedenting_interpolating_heredoc_fake_line_continuation.txt4
-rw-r--r--test/prism/fixtures/whitequark/dedenting_non_interpolating_heredoc_line_continuation.txt4
-rw-r--r--test/prism/fixtures/whitequark/def.txt11
-rw-r--r--test/prism/fixtures/whitequark/defined.txt5
-rw-r--r--test/prism/fixtures/whitequark/defs.txt9
-rw-r--r--test/prism/fixtures/whitequark/emit_arg_inside_procarg0_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/empty_stmt.txt1
-rw-r--r--test/prism/fixtures/whitequark/endless_comparison_method.txt11
-rw-r--r--test/prism/fixtures/whitequark/endless_method.txt7
-rw-r--r--test/prism/fixtures/whitequark/endless_method_command_syntax.txt15
-rw-r--r--test/prism/fixtures/whitequark/endless_method_forwarded_args_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/endless_method_with_rescue_mod.txt3
-rw-r--r--test/prism/fixtures/whitequark/endless_method_without_args.txt7
-rw-r--r--test/prism/fixtures/whitequark/ensure.txt1
-rw-r--r--test/prism/fixtures/whitequark/ensure_empty.txt1
-rw-r--r--test/prism/fixtures/whitequark/false.txt1
-rw-r--r--test/prism/fixtures/whitequark/find_pattern.txt7
-rw-r--r--test/prism/fixtures/whitequark/float.txt3
-rw-r--r--test/prism/fixtures/whitequark/for.txt3
-rw-r--r--test/prism/fixtures/whitequark/for_mlhs.txt1
-rw-r--r--test/prism/fixtures/whitequark/forward_arg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forward_arg_with_open_args.txt27
-rw-r--r--test/prism/fixtures/whitequark/forward_args_legacy.txt5
-rw-r--r--test/prism/fixtures/whitequark/forwarded_argument_with_kwrestarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forwarded_argument_with_restarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forwarded_kwrestarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forwarded_kwrestarg_with_additional_kwarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forwarded_restarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/gvar.txt1
-rw-r--r--test/prism/fixtures/whitequark/gvasgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/hash_empty.txt1
-rw-r--r--test/prism/fixtures/whitequark/hash_hashrocket.txt3
-rw-r--r--test/prism/fixtures/whitequark/hash_kwsplat.txt1
-rw-r--r--test/prism/fixtures/whitequark/hash_label.txt1
-rw-r--r--test/prism/fixtures/whitequark/hash_label_end.txt5
-rw-r--r--test/prism/fixtures/whitequark/hash_pair_value_omission.txt5
-rw-r--r--test/prism/fixtures/whitequark/heredoc.txt14
-rw-r--r--test/prism/fixtures/whitequark/if.txt3
-rw-r--r--test/prism/fixtures/whitequark/if_else.txt3
-rw-r--r--test/prism/fixtures/whitequark/if_elsif.txt1
-rw-r--r--test/prism/fixtures/whitequark/if_masgn__24.txt1
-rw-r--r--test/prism/fixtures/whitequark/if_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/if_nl_then.txt2
-rw-r--r--test/prism/fixtures/whitequark/int.txt5
-rw-r--r--test/prism/fixtures/whitequark/int___LINE__.txt1
-rw-r--r--test/prism/fixtures/whitequark/interp_digit_var.txt87
-rw-r--r--test/prism/fixtures/whitequark/ivar.txt1
-rw-r--r--test/prism/fixtures/whitequark/ivasgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/keyword_argument_omission.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwarg_combinations.txt7
-rw-r--r--test/prism/fixtures/whitequark/kwarg_no_paren.txt5
-rw-r--r--test/prism/fixtures/whitequark/kwbegin_compstmt.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwnilarg.txt5
-rw-r--r--test/prism/fixtures/whitequark/kwoptarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwrestarg_named.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwrestarg_unnamed.txt1
-rw-r--r--test/prism/fixtures/whitequark/lbrace_arg_after_command_args.txt1
-rw-r--r--test/prism/fixtures/whitequark/lparenarg_after_lvar__since_25.txt3
-rw-r--r--test/prism/fixtures/whitequark/lvar.txt1
-rw-r--r--test/prism/fixtures/whitequark/lvar_injecting_match.txt3
-rw-r--r--test/prism/fixtures/whitequark/lvasgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/marg_combinations.txt19
-rw-r--r--test/prism/fixtures/whitequark/masgn.txt5
-rw-r--r--test/prism/fixtures/whitequark/masgn_attr.txt5
-rw-r--r--test/prism/fixtures/whitequark/masgn_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/masgn_const.txt3
-rw-r--r--test/prism/fixtures/whitequark/masgn_nested.txt3
-rw-r--r--test/prism/fixtures/whitequark/masgn_splat.txt19
-rw-r--r--test/prism/fixtures/whitequark/method_definition_in_while_cond.txt7
-rw-r--r--test/prism/fixtures/whitequark/module.txt1
-rw-r--r--test/prism/fixtures/whitequark/multiple_args_with_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/whitequark/multiple_pattern_matches.txt5
-rw-r--r--test/prism/fixtures/whitequark/newline_in_hash_argument.txt14
-rw-r--r--test/prism/fixtures/whitequark/nil.txt1
-rw-r--r--test/prism/fixtures/whitequark/nil_expression.txt3
-rw-r--r--test/prism/fixtures/whitequark/non_lvar_injecting_match.txt1
-rw-r--r--test/prism/fixtures/whitequark/not.txt5
-rw-r--r--test/prism/fixtures/whitequark/not_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/not_masgn__24.txt1
-rw-r--r--test/prism/fixtures/whitequark/nth_ref.txt1
-rw-r--r--test/prism/fixtures/whitequark/numbered_args_after_27.txt7
-rw-r--r--test/prism/fixtures/whitequark/numparam_outside_block.txt9
-rw-r--r--test/prism/fixtures/whitequark/numparam_ruby_bug_19025.txt1
-rw-r--r--test/prism/fixtures/whitequark/op_asgn.txt5
-rw-r--r--test/prism/fixtures/whitequark/op_asgn_cmd.txt7
-rw-r--r--test/prism/fixtures/whitequark/op_asgn_index.txt1
-rw-r--r--test/prism/fixtures/whitequark/op_asgn_index_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/optarg.txt3
-rw-r--r--test/prism/fixtures/whitequark/or.txt3
-rw-r--r--test/prism/fixtures/whitequark/or_asgn.txt3
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_272.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_490.txt5
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_507.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_518.txt2
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_525.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_604.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_640.txt4
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_645.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_830.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_989.txt3
-rw-r--r--test/prism/fixtures/whitequark/parser_drops_truncated_parts_of_squiggly_heredoc.txt3
-rw-r--r--test/prism/fixtures/whitequark/parser_slash_slash_n_escaping_in_literals.txt62
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching__FILE__LINE_literals.txt4
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_blank_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_const_pattern.txt11
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_constants.txt5
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_explicit_array_match.txt19
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_expr_in_paren.txt1
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_hash.txt48
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_if_unless_modifiers.txt3
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_implicit_array_match.txt15
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_keyword_variable.txt1
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_lambda.txt1
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_match_alt.txt1
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_match_as.txt1
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_nil_pattern.txt1
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_no_body.txt1
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_ranges.txt11
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_single_line.txt3
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_single_line_allowed_omission_of_parentheses.txt11
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_single_match.txt1
-rw-r--r--test/prism/fixtures/whitequark/pin_expr.txt14
-rw-r--r--test/prism/fixtures/whitequark/postexe.txt1
-rw-r--r--test/prism/fixtures/whitequark/preexe.txt1
-rw-r--r--test/prism/fixtures/whitequark/procarg0.txt3
-rw-r--r--test/prism/fixtures/whitequark/procarg0_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/range_exclusive.txt1
-rw-r--r--test/prism/fixtures/whitequark/range_inclusive.txt1
-rw-r--r--test/prism/fixtures/whitequark/rational.txt3
-rw-r--r--test/prism/fixtures/whitequark/regex_interp.txt1
-rw-r--r--test/prism/fixtures/whitequark/regex_plain.txt1
-rw-r--r--test/prism/fixtures/whitequark/resbody_list.txt1
-rw-r--r--test/prism/fixtures/whitequark/resbody_list_mrhs.txt1
-rw-r--r--test/prism/fixtures/whitequark/resbody_list_var.txt1
-rw-r--r--test/prism/fixtures/whitequark/resbody_var.txt3
-rw-r--r--test/prism/fixtures/whitequark/rescue.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_else_ensure.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_ensure.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_in_lambda_block.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_mod_asgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_mod_masgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_mod_op_assign.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_without_begin_end.txt1
-rw-r--r--test/prism/fixtures/whitequark/restarg_named.txt1
-rw-r--r--test/prism/fixtures/whitequark/restarg_unnamed.txt1
-rw-r--r--test/prism/fixtures/whitequark/return.txt7
-rw-r--r--test/prism/fixtures/whitequark/return_block.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_10279.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_10653.txt5
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11107.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11380.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11873.txt23
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11873_a.txt39
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11873_b.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11989.txt3
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11990.txt3
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_12073.txt3
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_12402.txt27
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_12669.txt7
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_12686.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_13547.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_14690.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_15789.txt3
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_18878.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_19281.txt7
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_19539.txt9
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_9669.txt8
-rw-r--r--test/prism/fixtures/whitequark/sclass.txt1
-rw-r--r--test/prism/fixtures/whitequark/self.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_attr_asgn.txt7
-rw-r--r--test/prism/fixtures/whitequark/send_attr_asgn_conditional.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_binary_op.txt41
-rw-r--r--test/prism/fixtures/whitequark/send_block_chain_cmd.txt13
-rw-r--r--test/prism/fixtures/whitequark/send_block_conditional.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_call.txt3
-rw-r--r--test/prism/fixtures/whitequark/send_conditional.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index_asgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index_asgn_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_lambda.txt5
-rw-r--r--test/prism/fixtures/whitequark/send_lambda_args.txt3
-rw-r--r--test/prism/fixtures/whitequark/send_lambda_args_noparen.txt3
-rw-r--r--test/prism/fixtures/whitequark/send_lambda_args_shadow.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_lambda_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_op_asgn_conditional.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_plain.txt5
-rw-r--r--test/prism/fixtures/whitequark/send_plain_cmd.txt5
-rw-r--r--test/prism/fixtures/whitequark/send_self.txt5
-rw-r--r--test/prism/fixtures/whitequark/send_self_block.txt7
-rw-r--r--test/prism/fixtures/whitequark/send_unary_op.txt5
-rw-r--r--test/prism/fixtures/whitequark/slash_newline_in_heredocs.txt13
-rw-r--r--test/prism/fixtures/whitequark/space_args_arg.txt1
-rw-r--r--test/prism/fixtures/whitequark/space_args_arg_block.txt5
-rw-r--r--test/prism/fixtures/whitequark/space_args_arg_call.txt1
-rw-r--r--test/prism/fixtures/whitequark/space_args_arg_newline.txt2
-rw-r--r--test/prism/fixtures/whitequark/space_args_block.txt1
-rw-r--r--test/prism/fixtures/whitequark/space_args_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/string___FILE__.txt1
-rw-r--r--test/prism/fixtures/whitequark/string_concat.txt1
-rw-r--r--test/prism/fixtures/whitequark/string_dvar.txt1
-rw-r--r--test/prism/fixtures/whitequark/string_interp.txt1
-rw-r--r--test/prism/fixtures/whitequark/string_plain.txt3
-rw-r--r--test/prism/fixtures/whitequark/super.txt5
-rw-r--r--test/prism/fixtures/whitequark/super_block.txt3
-rw-r--r--test/prism/fixtures/whitequark/symbol_interp.txt1
-rw-r--r--test/prism/fixtures/whitequark/symbol_plain.txt3
-rw-r--r--test/prism/fixtures/whitequark/ternary.txt1
-rw-r--r--test/prism/fixtures/whitequark/ternary_ambiguous_symbol.txt1
-rw-r--r--test/prism/fixtures/whitequark/trailing_forward_arg.txt1
-rw-r--r--test/prism/fixtures/whitequark/true.txt1
-rw-r--r--test/prism/fixtures/whitequark/unary_num_pow_precedence.txt5
-rw-r--r--test/prism/fixtures/whitequark/undef.txt1
-rw-r--r--test/prism/fixtures/whitequark/unless.txt3
-rw-r--r--test/prism/fixtures/whitequark/unless_else.txt3
-rw-r--r--test/prism/fixtures/whitequark/unless_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/until.txt3
-rw-r--r--test/prism/fixtures/whitequark/until_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/until_post.txt1
-rw-r--r--test/prism/fixtures/whitequark/var_and_asgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/var_op_asgn.txt7
-rw-r--r--test/prism/fixtures/whitequark/var_op_asgn_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/var_or_asgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/when_multi.txt1
-rw-r--r--test/prism/fixtures/whitequark/when_splat.txt1
-rw-r--r--test/prism/fixtures/whitequark/when_then.txt1
-rw-r--r--test/prism/fixtures/whitequark/while.txt3
-rw-r--r--test/prism/fixtures/whitequark/while_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/while_post.txt1
-rw-r--r--test/prism/fixtures/whitequark/xstring_interp.txt1
-rw-r--r--test/prism/fixtures/whitequark/xstring_plain.txt1
-rw-r--r--test/prism/fixtures/whitequark/zsuper.txt1
-rw-r--r--test/prism/fixtures/write_command_operator.txt3
-rw-r--r--test/prism/fixtures/xstring.txt21
-rw-r--r--test/prism/fixtures/xstring_with_backslash.txt1
-rw-r--r--test/prism/fixtures/yield.txt7
-rw-r--r--test/prism/fixtures_test.rb38
-rw-r--r--test/prism/fuzzer_test.rb67
-rw-r--r--test/prism/heredoc_dedent_test.rb134
-rw-r--r--test/prism/lex_test.rb123
-rw-r--r--test/prism/library_symbols_test.rb104
-rw-r--r--test/prism/locals_test.rb245
-rw-r--r--test/prism/magic_comment_test.rb122
-rw-r--r--test/prism/newline_offsets_test.rb45
-rw-r--r--test/prism/newline_test.rb101
-rw-r--r--test/prism/onigmo_test.rb66
-rw-r--r--test/prism/percent_delimiter_string_test.rb82
-rw-r--r--test/prism/ractor_test.rb74
-rw-r--r--test/prism/regexp_test.rb265
-rw-r--r--test/prism/result/attribute_write_test.rb56
-rw-r--r--test/prism/result/breadth_first_search_test.rb29
-rw-r--r--test/prism/result/comments_test.rb138
-rw-r--r--test/prism/result/constant_path_node_test.rb91
-rw-r--r--test/prism/result/continuable_test.rb124
-rw-r--r--test/prism/result/equality_test.rb22
-rw-r--r--test/prism/result/error_recovery_test.rb237
-rw-r--r--test/prism/result/heredoc_test.rb19
-rw-r--r--test/prism/result/implicit_array_test.rb59
-rw-r--r--test/prism/result/index_write_test.rb89
-rw-r--r--test/prism/result/integer_base_flags_test.rb33
-rw-r--r--test/prism/result/integer_parse_test.rb41
-rw-r--r--test/prism/result/named_capture_test.rb29
-rw-r--r--test/prism/result/node_id_test.rb27
-rw-r--r--test/prism/result/numeric_value_test.rb32
-rw-r--r--test/prism/result/overlap_test.rb48
-rw-r--r--test/prism/result/regular_expression_options_test.rb25
-rw-r--r--test/prism/result/source_location_test.rb954
-rw-r--r--test/prism/result/static_inspect_test.rb89
-rw-r--r--test/prism/result/static_literals_test.rb92
-rw-r--r--test/prism/result/string_test.rb32
-rw-r--r--test/prism/result/warnings_test.rb451
-rw-r--r--test/prism/ruby/compiler_test.rb31
-rw-r--r--test/prism/ruby/desugar_compiler_test.rb80
-rw-r--r--test/prism/ruby/dispatcher_test.rb55
-rw-r--r--test/prism/ruby/find_fixtures.rb69
-rw-r--r--test/prism/ruby/find_test.rb242
-rw-r--r--test/prism/ruby/location_test.rb254
-rw-r--r--test/prism/ruby/parameters_signature_test.rb105
-rw-r--r--test/prism/ruby/parser_test.rb323
-rw-r--r--test/prism/ruby/pattern_test.rb132
-rw-r--r--test/prism/ruby/reflection_test.rb22
-rw-r--r--test/prism/ruby/relocation_test.rb192
-rw-r--r--test/prism/ruby/ripper_test.rb309
-rw-r--r--test/prism/ruby/ruby_parser_test.rb140
-rw-r--r--test/prism/ruby/source_test.rb51
-rw-r--r--test/prism/ruby/string_query_test.rb60
-rw-r--r--test/prism/ruby/tunnel_test.rb26
-rw-r--r--test/prism/snippets_test.rb43
-rw-r--r--test/prism/test_helper.rb386
-rw-r--r--test/prism/unescape_test.rb245
-rw-r--r--test/prism/version_test.rb11
1402 files changed, 17902 insertions, 0 deletions
diff --git a/test/prism/api/command_line_test.rb b/test/prism/api/command_line_test.rb
new file mode 100644
index 0000000000..e53d18703a
--- /dev/null
+++ b/test/prism/api/command_line_test.rb
@@ -0,0 +1,114 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class CommandLineTest < TestCase
+ def test_command_line_p
+ program = Prism.parse("1", command_line: "p").value
+ statements = program.statements.body
+
+ assert_equal 2, statements.length
+ assert_kind_of CallNode, statements.last
+ assert_equal :print, statements.last.name
+ end
+
+ def test_command_line_n
+ program = Prism.parse("1", command_line: "n").value
+ statements = program.statements.body
+
+ assert_equal 1, statements.length
+ assert_kind_of WhileNode, statements.first
+
+ predicate = statements.first.predicate
+ assert_kind_of CallNode, predicate
+ assert_equal :gets, predicate.name
+
+ arguments = predicate.arguments.arguments
+ assert_equal 1, arguments.length
+ assert_equal :$/, arguments.first.name
+ end
+
+ def test_command_line_a
+ program = Prism.parse("1", command_line: "na").value
+ statements = program.statements.body
+
+ assert_equal 1, statements.length
+ assert_kind_of WhileNode, statements.first
+
+ statement = statements.first.statements.body.first
+ assert_kind_of GlobalVariableWriteNode, statement
+ assert_equal :$F, statement.name
+ end
+
+ def test_command_line_l
+ program = Prism.parse("1", command_line: "nl").value
+ statements = program.statements.body
+
+ assert_equal 1, statements.length
+ assert_kind_of WhileNode, statements.first
+
+ predicate = statements.first.predicate
+ assert_kind_of CallNode, predicate
+ assert_equal :gets, predicate.name
+
+ arguments = predicate.arguments
+ assert arguments.contains_keywords?
+
+ arguments = predicate.arguments.arguments
+ assert_equal 2, arguments.length
+ assert_equal :$/, arguments.first.name
+ assert_equal "chomp", arguments.last.elements.first.key.unescaped
+ end
+
+ def test_command_line_e
+ result = Prism.parse("1 if 2..3")
+ assert_equal 2, result.warnings.length
+
+ result = Prism.parse("1 if 2..3", command_line: "e")
+ assert_equal 0, result.warnings.length
+ end
+
+ def test_command_line_x_implicit
+ result = Prism.parse_statement(<<~RUBY, main_script: true)
+ #!/bin/bash
+ exit 1
+
+ #!/usr/bin/env ruby
+ 1
+ RUBY
+
+ assert_kind_of IntegerNode, result
+ end
+
+ def test_command_line_x_explicit
+ result = Prism.parse_statement(<<~RUBY, command_line: "x")
+ exit 1
+
+ #!/usr/bin/env ruby
+ 1
+ RUBY
+
+ assert_kind_of IntegerNode, result
+ end
+
+ def test_command_line_x_implicit_fail
+ result = Prism.parse(<<~RUBY, main_script: true)
+ #!/bin/bash
+ exit 1
+ RUBY
+
+ assert_equal 1, result.errors.length
+ assert_equal :load, result.errors.first.level
+ end
+
+ def test_command_line_x_explicit_fail
+ result = Prism.parse(<<~RUBY, command_line: "x")
+ exit 1
+ RUBY
+
+ assert_equal 1, result.errors.length
+ assert_equal :load, result.errors.first.level
+ end
+ end
+end
diff --git a/test/prism/api/dump_test.rb b/test/prism/api/dump_test.rb
new file mode 100644
index 0000000000..941088e159
--- /dev/null
+++ b/test/prism/api/dump_test.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+return if ENV["PRISM_BUILD_MINIMAL"]
+
+require_relative "../test_helper"
+
+module Prism
+ class DumpTest < TestCase
+ Fixture.each do |fixture|
+ define_method(fixture.test_name) { assert_dump(fixture) }
+ end
+
+ def test_dump
+ filepath = __FILE__
+ source = File.read(filepath, binmode: true, external_encoding: Encoding::UTF_8)
+
+ assert_equal Prism.lex(source, filepath: filepath).value, Prism.lex_file(filepath).value
+ assert_equal Prism.dump(source, filepath: filepath), Prism.dump_file(filepath)
+
+ serialized = Prism.dump(source, filepath: filepath)
+ ast1 = Prism.load(source, serialized).value
+ ast2 = Prism.parse(source, filepath: filepath).value
+ ast3 = Prism.parse_file(filepath).value
+
+ assert_equal_nodes ast1, ast2
+ assert_equal_nodes ast2, ast3
+ end
+
+ def test_dump_file
+ assert_nothing_raised do
+ Prism.dump_file(__FILE__)
+ end
+
+ error = assert_raise Errno::ENOENT do
+ Prism.dump_file("idontexist.rb")
+ end
+
+ assert_equal "No such file or directory - idontexist.rb", error.message
+
+ assert_raise TypeError do
+ Prism.dump_file(nil)
+ end
+ end
+
+ private
+
+ def assert_dump(fixture)
+ source = fixture.read
+
+ result = Prism.parse(source, filepath: fixture.path)
+ dumped = Prism.dump(source, filepath: fixture.path)
+
+ assert_equal_nodes(result.value, Prism.load(source, dumped).value)
+ end
+ end
+end
diff --git a/test/prism/api/freeze_test.rb b/test/prism/api/freeze_test.rb
new file mode 100644
index 0000000000..bf91792e69
--- /dev/null
+++ b/test/prism/api/freeze_test.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class FreezeTest < TestCase
+ def test_parse
+ assert_frozen(Prism.parse("1 + 2; %i{foo} + %i{bar}", freeze: true))
+ end
+
+ def test_offsets_usable
+ node = Prism.parse_statement("1 + 2", freeze: true)
+ assert_equal(1, node.start_line)
+ end
+
+ def test_lex
+ assert_frozen(Prism.lex("1 + 2; %i{foo} + %i{bar}", freeze: true))
+ end
+
+ def test_parse_lex
+ assert_frozen(Prism.parse_lex("1 + 2; %i{foo} + %i{bar}", freeze: true))
+ assert_frozen(Prism.parse_lex("# encoding: euc-jp\n%i{foo}", freeze: true))
+ end
+
+ def test_parse_comments
+ assert_frozen(Prism.parse_comments("# comment", freeze: true))
+ end
+
+ def test_parse_stream
+ assert_frozen(Prism.parse_stream(StringIO.new("1 + 2; %i{foo} + %i{bar}"), freeze: true))
+ end
+
+ if !ENV["PRISM_BUILD_MINIMAL"]
+ def test_dump
+ assert_frozen(Prism.dump("1 + 2; %i{foo} + %i{bar}", freeze: true))
+ end
+ end
+
+ private
+
+ def assert_frozen_each(value)
+ assert_predicate value, :frozen?
+
+ value.instance_variables.each do |name|
+ case (child = value.instance_variable_get(name))
+ when Array
+ child.each { |item| assert_frozen_each(item) }
+ when Hash
+ child.each { |key, item| assert_frozen_each(key); assert_frozen_each(item) }
+ else
+ assert_frozen_each(child)
+ end
+ end
+ end
+
+ if defined?(Ractor.shareable?)
+ def assert_frozen(value)
+ assert_frozen_each(value)
+ assert Ractor.shareable?(value), -> { binding.irb }
+ end
+ else
+ alias assert_frozen assert_frozen_each
+ end
+ end
+end
diff --git a/test/prism/api/lex_test.rb b/test/prism/api/lex_test.rb
new file mode 100644
index 0000000000..0b675b215f
--- /dev/null
+++ b/test/prism/api/lex_test.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class LexTest < TestCase
+ def test_lex_result
+ result = Prism.lex("")
+ assert_kind_of LexResult, result
+
+ result = Prism.lex_file(__FILE__)
+ assert_kind_of LexResult, result
+ end
+
+ def test_parse_lex_result
+ result = Prism.parse_lex("")
+ assert_kind_of ParseLexResult, result
+
+ result = Prism.parse_lex_file(__FILE__)
+ assert_kind_of ParseLexResult, result
+ end
+ end
+end
diff --git a/test/prism/api/parse_comments_test.rb b/test/prism/api/parse_comments_test.rb
new file mode 100644
index 0000000000..4dbcca1827
--- /dev/null
+++ b/test/prism/api/parse_comments_test.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ParseCommentsTest < TestCase
+ def test_parse_comments
+ comments = Prism.parse_comments("# foo")
+
+ assert_kind_of Array, comments
+ assert_equal 1, comments.length
+ end
+
+ def test_parse_file_comments
+ comments = Prism.parse_file_comments(__FILE__)
+
+ assert_kind_of Array, comments
+ assert_equal 1, comments.length
+ end
+
+ def test_parse_file_comments_error
+ error = assert_raise Errno::ENOENT do
+ Prism.parse_file_comments("idontexist.rb")
+ end
+
+ assert_equal "No such file or directory - idontexist.rb", error.message
+
+ assert_raise TypeError do
+ Prism.parse_file_comments(nil)
+ end
+ end
+ end
+end
diff --git a/test/prism/api/parse_stream_test.rb b/test/prism/api/parse_stream_test.rb
new file mode 100644
index 0000000000..3bc86fbd61
--- /dev/null
+++ b/test/prism/api/parse_stream_test.rb
@@ -0,0 +1,118 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ParseStreamTest < TestCase
+ def test_single_line
+ io = StringIO.new("1 + 2")
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_kind_of Prism::CallNode, result.statement
+ end
+
+ def test_multi_line
+ io = StringIO.new("1 + 2\n3 + 4")
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_kind_of Prism::CallNode, result.statement
+ assert_kind_of Prism::CallNode, result.statement
+ end
+
+ def test_multi_read
+ io = StringIO.new("a" * 4096 * 4)
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_kind_of Prism::CallNode, result.statement
+ end
+
+ def test___END__
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ __END__
+ 5 + 6
+ RUBY
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_equal 2, result.value.statements.body.length
+ assert_equal "5 + 6\n", io.read
+ end
+
+ def test_false___END___in_string
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ "
+ __END__
+ "
+ 5 + 6
+ RUBY
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_equal 4, result.value.statements.body.length
+ end
+
+ def test_false___END___in_regexp
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ /
+ __END__
+ /
+ 5 + 6
+ RUBY
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_equal 4, result.value.statements.body.length
+ end
+
+ def test_false___END___in_list
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ %w[
+ __END__
+ ]
+ 5 + 6
+ RUBY
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_equal 4, result.value.statements.body.length
+ end
+
+ def test_false___END___in_heredoc
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ <<-EOF
+ __END__
+ EOF
+ 5 + 6
+ RUBY
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_equal 4, result.value.statements.body.length
+ end
+
+ def test_nul_bytes
+ io = StringIO.new(<<~RUBY)
+ 1 # \0\0\0\t
+ 2 # \0\0\0
+ 3
+ RUBY
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_equal 3, result.value.statements.body.length
+ end
+ end
+end
diff --git a/test/prism/api/parse_success_test.rb b/test/prism/api/parse_success_test.rb
new file mode 100644
index 0000000000..2caaa5136e
--- /dev/null
+++ b/test/prism/api/parse_success_test.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ParseSuccessTest < TestCase
+ def test_parse_success?
+ assert Prism.parse_success?("1")
+ refute Prism.parse_success?("<>")
+ end
+
+ def test_parse_file_success?
+ assert Prism.parse_file_success?(__FILE__)
+ end
+ end
+end
diff --git a/test/prism/api/parse_test.rb b/test/prism/api/parse_test.rb
new file mode 100644
index 0000000000..c9a47c1a61
--- /dev/null
+++ b/test/prism/api/parse_test.rb
@@ -0,0 +1,189 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ParseTest < TestCase
+ def test_parse_result
+ result = Prism.parse("")
+ assert_kind_of ParseResult, result
+
+ result = Prism.parse_file(__FILE__)
+ assert_kind_of ParseResult, result
+ end
+
+ def test_parse_empty_string
+ result = Prism.parse("")
+ assert_equal [], result.value.statements.body
+ end
+
+ def test_parse_takes_file_path
+ filepath = "filepath.rb"
+ result = Prism.parse("def foo; __FILE__; end", filepath: filepath)
+
+ assert_equal filepath, find_source_file_node(result.value).filepath
+ end
+
+ def test_parse_takes_line
+ line = 4
+ result = Prism.parse("def foo\n __FILE__\nend", line: line)
+
+ assert_equal line, result.value.location.start_line
+ assert_equal line + 1, find_source_file_node(result.value).location.start_line
+
+ result = Prism.parse_lex("def foo\n __FILE__\nend", line: line)
+ assert_equal line, result.value.first.location.start_line
+ end
+
+ def test_parse_takes_negative_lines
+ line = -2
+ result = Prism.parse("def foo\n __FILE__\nend", line: line)
+
+ assert_equal line, result.value.location.start_line
+ assert_equal line + 1, find_source_file_node(result.value).location.start_line
+
+ result = Prism.parse_lex("def foo\n __FILE__\nend", line: line)
+ assert_equal line, result.value.first.location.start_line
+ end
+
+ def test_parse_file
+ node = Prism.parse_file(__FILE__).value
+ assert_kind_of ProgramNode, node
+
+ error = assert_raise Errno::ENOENT do
+ Prism.parse_file("idontexist.rb")
+ end
+
+ assert_equal "No such file or directory - idontexist.rb", error.message
+
+ assert_raise TypeError do
+ Prism.parse_file(nil)
+ end
+ end
+
+ def test_parse_tempfile
+ Tempfile.create(["test_parse_tempfile", ".rb"]) do |t|
+ t.puts ["begin\n", " end\n"]
+ t.flush
+ Prism.parse_file(t.path)
+ end
+ end
+
+ if RUBY_ENGINE != "truffleruby"
+ def test_parse_nonascii
+ Dir.mktmpdir do |dir|
+ path = File.join(dir, "\u{3042 3044 3046 3048 304a}.rb".encode(Encoding::Windows_31J))
+ File.write(path, "ok")
+ Prism.parse_file(path)
+ end
+ end
+ end
+
+ def test_parse_directory
+ error = nil
+
+ begin
+ Prism.parse_file(__dir__)
+ rescue SystemCallError => error
+ end
+
+ assert_kind_of Errno::EISDIR, error
+ end
+
+ def test_partial_script
+ assert Prism.parse_failure?("break")
+ assert Prism.parse_success?("break", partial_script: true)
+
+ assert Prism.parse_failure?("next")
+ assert Prism.parse_success?("next", partial_script: true)
+
+ assert Prism.parse_failure?("redo")
+ assert Prism.parse_success?("redo", partial_script: true)
+
+ assert Prism.parse_failure?("yield")
+ assert Prism.parse_success?("yield", partial_script: true)
+ end
+
+ def test_version
+ assert Prism.parse_success?("1 + 1", version: "3.3")
+ assert Prism.parse_success?("1 + 1", version: "3.3.0")
+ assert Prism.parse_success?("1 + 1", version: "3.3.1")
+ assert Prism.parse_success?("1 + 1", version: "3.3.9")
+ assert Prism.parse_success?("1 + 1", version: "3.3.10")
+
+ assert Prism.parse_success?("1 + 1", version: "3.4")
+ assert Prism.parse_success?("1 + 1", version: "3.4.0")
+ assert Prism.parse_success?("1 + 1", version: "3.4.9")
+ assert Prism.parse_success?("1 + 1", version: "3.4.10")
+
+ assert Prism.parse_success?("1 + 1", version: "3.5")
+ assert Prism.parse_success?("1 + 1", version: "3.5.0")
+
+ assert Prism.parse_success?("1 + 1", version: "4.0")
+ assert Prism.parse_success?("1 + 1", version: "4.0.0")
+
+ assert Prism.parse_success?("1 + 1", version: "4.1")
+ assert Prism.parse_success?("1 + 1", version: "4.1.0")
+
+ assert Prism.parse_success?("1 + 1", version: "latest")
+
+ # Test edge case
+ error = assert_raise(ArgumentError) { Prism.parse("1 + 1", version: "latest2") }
+ assert_equal "invalid version: latest2", error.message
+
+ assert_raise ArgumentError do
+ Prism.parse("1 + 1", version: "3.3.a")
+ end
+
+ # Not supported version (too old)
+ assert_raise ArgumentError do
+ Prism.parse("1 + 1", version: "3.2.0")
+ end
+
+ # Not supported version (too new)
+ assert_raise ArgumentError do
+ Prism.parse("1 + 1", version: "3.6.0")
+ end
+ end
+
+ def test_version_current
+ if RUBY_VERSION >= "3.3"
+ assert Prism.parse_success?("1 + 1", version: "current")
+ else
+ assert_raise(CurrentVersionError) { Prism.parse_success?("1 + 1", version: "current") }
+ end
+ end
+
+ def test_nearest
+ assert Prism.parse_success?("1 + 1", version: "nearest")
+ end
+
+ def test_scopes
+ assert_kind_of Prism::CallNode, Prism.parse_statement("foo")
+ assert_kind_of Prism::LocalVariableReadNode, Prism.parse_statement("foo", scopes: [[:foo]])
+ assert_kind_of Prism::LocalVariableReadNode, Prism.parse_statement("foo", scopes: [Prism.scope(locals: [:foo])])
+
+ assert Prism.parse_failure?("foo(*)")
+ assert Prism.parse_success?("foo(*)", scopes: [Prism.scope(forwarding: [:*])])
+
+ assert Prism.parse_failure?("foo(**)")
+ assert Prism.parse_success?("foo(**)", scopes: [Prism.scope(forwarding: [:**])])
+
+ assert Prism.parse_failure?("foo(&)")
+ assert Prism.parse_success?("foo(&)", scopes: [Prism.scope(forwarding: [:&])])
+
+ assert Prism.parse_failure?("foo(...)")
+ assert Prism.parse_success?("foo(...)", scopes: [Prism.scope(forwarding: [:"..."])])
+ end
+
+ private
+
+ def find_source_file_node(program)
+ queue = [program]
+ while (node = queue.shift)
+ return node if node.is_a?(SourceFileNode)
+ queue.concat(node.compact_child_nodes)
+ end
+ end
+ end
+end
diff --git a/test/prism/bom_test.rb b/test/prism/bom_test.rb
new file mode 100644
index 0000000000..0fa00ae4e8
--- /dev/null
+++ b/test/prism/bom_test.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+# Don't bother checking this on these engines, this is such a specific Ripper
+# test.
+return if RUBY_ENGINE != "ruby"
+
+require_relative "test_helper"
+require "ripper"
+
+module Prism
+ class BOMTest < TestCase
+ def test_ident
+ assert_bom("foo")
+ end
+
+ def test_back_reference
+ assert_bom("$+")
+ end
+
+ def test_instance_variable
+ assert_bom("@foo")
+ end
+
+ def test_class_variable
+ assert_bom("@@foo")
+ end
+
+ def test_global_variable
+ assert_bom("$foo")
+ end
+
+ def test_numbered_reference
+ assert_bom("$1")
+ end
+
+ def test_percents
+ assert_bom("%i[]")
+ assert_bom("%r[]")
+ assert_bom("%s[]")
+ assert_bom("%q{}")
+ assert_bom("%w[]")
+ assert_bom("%x[]")
+ assert_bom("%I[]")
+ assert_bom("%W[]")
+ assert_bom("%Q{}")
+ end
+
+ def test_string
+ assert_bom("\"\"")
+ assert_bom("''")
+ end
+
+ private
+
+ def assert_bom(source)
+ bommed = "\xEF\xBB\xBF#{source}"
+ assert_equal Ripper.lex(bommed), Prism.lex_compat(bommed).value
+ end
+ end
+end
diff --git a/test/prism/encoding/encodings_test.rb b/test/prism/encoding/encodings_test.rb
new file mode 100644
index 0000000000..b008fc3fa1
--- /dev/null
+++ b/test/prism/encoding/encodings_test.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+return if RUBY_ENGINE != "ruby"
+
+require_relative "../test_helper"
+
+module Prism
+ class EncodingsTest < TestCase
+ class ConstantContext < BasicObject
+ def self.const_missing(const)
+ const
+ end
+ end
+
+ class IdentifierContext < BasicObject
+ def method_missing(name, *)
+ name
+ end
+ end
+
+ # These test that we're correctly parsing codepoints for each alias of each
+ # encoding that prism supports.
+ each_encoding do |encoding, range|
+ (encoding.names - %w[external internal filesystem locale]).each do |name|
+ define_method(:"test_encoding_#{name}") do
+ assert_encoding(encoding, name, range)
+ end
+ end
+ end
+
+ private
+
+ def assert_encoding_constant(name, character)
+ source = "# encoding: #{name}\n#{character}"
+ expected = ConstantContext.new.instance_eval(source)
+
+ result = Prism.parse(source)
+ assert result.success?
+
+ actual = result.value.statements.body.last
+ assert_kind_of ConstantReadNode, actual
+ assert_equal expected, actual.name
+ end
+
+ def assert_encoding_identifier(name, character)
+ source = "# encoding: #{name}\n#{character}"
+ expected = IdentifierContext.new.instance_eval(source)
+
+ result = Prism.parse(source)
+ assert result.success?
+
+ actual = result.value.statements.body.last
+ assert_kind_of CallNode, actual
+ assert_equal expected, actual.name
+ end
+
+ # Check that we can properly parse every codepoint in the given encoding.
+ def assert_encoding(encoding, name, range)
+ unicode = false
+
+ case encoding
+ when Encoding::UTF_8, Encoding::UTF_8_MAC, Encoding::UTF8_DoCoMo, Encoding::UTF8_KDDI, Encoding::UTF8_SoftBank, Encoding::CESU_8
+ unicode = true
+ when Encoding::Windows_1253
+ range = range.to_a - [0xb5]
+ end
+
+ range.each do |codepoint|
+ character = codepoint.chr(encoding)
+
+ if character.match?(/[[:alpha:]]/)
+ if character.match?(/[[:upper:]]/) || (unicode && character.match?(Regexp.new("\\p{Lt}".encode(encoding))))
+ assert_encoding_constant(name, character)
+ else
+ assert_encoding_identifier(name, character)
+ end
+ elsif character.match?(/[[:alnum:]]/)
+ assert_encoding_identifier(name, "_#{character}")
+ else
+ next if ["/", "{"].include?(character)
+
+ source = "# encoding: #{name}\n/(?##{character})/\n"
+ assert Prism.parse_success?(source), "Expected #{source.inspect} to parse successfully."
+ end
+ rescue RangeError
+ source = "# encoding: #{name}\n\\x#{codepoint.to_s(16)}"
+ assert Prism.parse_failure?(source)
+ end
+ end
+ end
+end
diff --git a/test/prism/encoding/regular_expression_encoding_test.rb b/test/prism/encoding/regular_expression_encoding_test.rb
new file mode 100644
index 0000000000..fdff1e3281
--- /dev/null
+++ b/test/prism/encoding/regular_expression_encoding_test.rb
@@ -0,0 +1,115 @@
+# frozen_string_literal: true
+
+return unless defined?(RubyVM::InstructionSequence)
+return if RubyVM::InstructionSequence.compile("").to_a[4][:parser] == :prism
+return if RUBY_VERSION < "3.2"
+
+require_relative "../test_helper"
+
+module Prism
+ class RegularExpressionEncodingTest < TestCase
+ each_encoding do |encoding, _|
+ define_method(:"test_regular_expression_encoding_flags_#{encoding.name}") do
+ assert_regular_expression_encoding_flags(encoding, ["/a/", "/ą/", "//"])
+ end
+
+ escapes = ["\\x00", "\\x7F", "\\x80", "\\xFF", "\\u{00}", "\\u{7F}", "\\u{80}", "\\M-\\C-?"]
+ escapes = escapes.concat(escapes.product(escapes).map(&:join))
+
+ define_method(:"test_regular_expression_escape_encoding_flags_#{encoding.name}") do
+ assert_regular_expression_encoding_flags(encoding, escapes.map { |e| "/#{e}/" })
+ end
+
+ ["n", "u", "e", "s"].each do |modifier|
+ define_method(:"test_regular_expression_encoding_modifiers_/#{modifier}_#{encoding.name}") do
+ regexp_sources = ["abc", "garçon", "\\x80", "gar\\xC3\\xA7on", "gar\\u{E7}on", "abc\\u{FFFFFF}", "\\x80\\u{80}", "\\p{L}" ]
+
+ assert_regular_expression_encoding_flags(
+ encoding,
+ regexp_sources.product(["n", "u", "e", "s"]).map { |r, modifier| "/#{r}/#{modifier}" }
+ )
+ end
+ end
+ end
+
+ private
+
+ def assert_regular_expression_encoding_flags(encoding, regexps)
+ regexps.each do |regexp|
+ source = "# encoding: #{encoding.name}\n#{regexp}"
+
+ encoding_errors = [
+ "invalid multibyte char", "escaped non ASCII character in UTF-8 regexp",
+ "differs from source encoding", "incompatible character encoding",
+ "invalid multibyte escape", "UTF-8 character in non UTF-8 regexp",
+ "invalid Unicode range", "non escaped non ASCII character",
+ "invalid character property name", "invalid Unicode list",
+ ]
+
+ expected =
+ begin
+ eval(source).encoding
+ rescue SyntaxError => error
+ if encoding_errors.find { |e| error.message.include?(e) }
+ error.message.split("\n").map { |m| m[/: (.+?)$/, 1] }
+ else
+ raise
+ end
+ end
+
+ actual =
+ Prism.parse(source).then do |result|
+ if result.success?
+ regexp = result.statement
+
+ actual_encoding = if regexp.forced_utf8_encoding?
+ Encoding::UTF_8
+ elsif regexp.forced_binary_encoding?
+ Encoding::ASCII_8BIT
+ elsif regexp.forced_us_ascii_encoding?
+ Encoding::US_ASCII
+ elsif regexp.ascii_8bit?
+ Encoding::ASCII_8BIT
+ elsif regexp.utf_8?
+ Encoding::UTF_8
+ elsif regexp.euc_jp?
+ Encoding::EUC_JP
+ elsif regexp.windows_31j?
+ Encoding::Windows_31J
+ else
+ encoding
+ end
+
+ if regexp.utf_8? && actual_encoding != Encoding::UTF_8
+ raise "expected regexp encoding to be UTF-8 due to '/u' modifier, but got #{actual_encoding.name}"
+ elsif regexp.ascii_8bit? && (actual_encoding != Encoding::ASCII_8BIT && actual_encoding != Encoding::US_ASCII)
+ raise "expected regexp encoding to be ASCII-8BIT or US-ASCII due to '/n' modifier, but got #{actual_encoding.name}"
+ elsif regexp.euc_jp? && actual_encoding != Encoding::EUC_JP
+ raise "expected regexp encoding to be EUC-JP due to '/e' modifier, but got #{actual_encoding.name}"
+ elsif regexp.windows_31j? && actual_encoding != Encoding::Windows_31J
+ raise "expected regexp encoding to be Windows-31J due to '/s' modifier, but got #{actual_encoding.name}"
+ end
+
+ if regexp.utf_8? && regexp.forced_utf8_encoding?
+ raise "the forced_utf8 flag should not be set when the UTF-8 modifier (/u) is used"
+ elsif regexp.ascii_8bit? && regexp.forced_binary_encoding?
+ raise "the forced_ascii_8bit flag should not be set when the UTF-8 modifier (/u) is used"
+ end
+
+ actual_encoding
+ else
+ errors = result.errors.map(&:message)
+
+ if errors.last&.include?("UTF-8 mixed within")
+ nil
+ else
+ errors
+ end
+ end
+ end
+
+ assert_equal expected, actual
+ end
+ end
+ end
+end
diff --git a/test/prism/encoding/string_encoding_test.rb b/test/prism/encoding/string_encoding_test.rb
new file mode 100644
index 0000000000..6f9d86df3b
--- /dev/null
+++ b/test/prism/encoding/string_encoding_test.rb
@@ -0,0 +1,136 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class StringEncodingTest < TestCase
+ each_encoding do |encoding, _|
+ define_method(:"test_#{encoding.name}") do
+ assert_encoding(encoding)
+ end
+ end
+
+ def test_coding
+ actual = Prism.parse_statement("# coding: utf-8\n'string'").unescaped.encoding
+ assert_equal Encoding::UTF_8, actual
+ end
+
+ def test_coding_with_whitespace
+ actual = Prism.parse_statement("# coding \t \r \v : \t \v \r ascii-8bit \n'string'").unescaped.encoding
+ assert_equal Encoding::ASCII_8BIT, actual
+ end
+
+ def test_emacs_style
+ actual = Prism.parse_statement("# -*- coding: utf-8 -*-\n'string'").unescaped.encoding
+ assert_equal Encoding::UTF_8, actual
+ end
+
+ def test_utf_8_unix
+ actual = Prism.parse_statement("# coding: utf-8-unix\n'string'").unescaped.encoding
+ assert_equal Encoding::UTF_8, actual
+ end
+
+ def test_utf_8_dos
+ actual = Prism.parse_statement("# coding: utf-8-dos\n'string'").unescaped.encoding
+ assert_equal Encoding::UTF_8, actual
+ end
+
+ def test_utf_8_mac
+ actual = Prism.parse_statement("# coding: utf-8-mac\n'string'").unescaped.encoding
+ assert_equal Encoding::UTF_8, actual
+ end
+
+ def test_utf_8_star
+ actual = Prism.parse_statement("# coding: utf-8-*\n'string'").unescaped.encoding
+ assert_equal Encoding::UTF_8, actual
+ end
+
+ def test_first_lexed_token
+ encoding = Prism.lex("# encoding: ascii-8bit").value[0][0].value.encoding
+ assert_equal Encoding::ASCII_8BIT, encoding
+ end
+
+ if !ENV["PRISM_BUILD_MINIMAL"]
+ # This test may be a little confusing. Basically when we use our strpbrk,
+ # it takes into account the encoding of the file.
+ def test_strpbrk_multibyte
+ result = Prism.parse(<<~RUBY)
+ # encoding: Shift_JIS
+ %w[\x81\x5c]
+ RUBY
+
+ assert(result.errors.empty?)
+ assert_equal(
+ (+"\x81\x5c").force_encoding(Encoding::Shift_JIS),
+ result.statement.elements.first.unescaped
+ )
+ end
+
+ def test_slice_encoding
+ slice = Prism.parse("# encoding: Shift_JIS\nア").value.slice
+ assert_equal (+"ア").force_encoding(Encoding::SHIFT_JIS), slice
+ assert_equal Encoding::SHIFT_JIS, slice.encoding
+ end
+
+ def test_multibyte_escapes
+ [
+ ["'", "'"],
+ ["\"", "\""],
+ ["`", "`"],
+ ["/", "/"],
+ ["<<'HERE'\n", "\nHERE"],
+ ["<<-HERE\n", "\nHERE"]
+ ].each do |opening, closing|
+ assert Prism.parse_success?("# encoding: shift_jis\n'\\\x82\xA0'\n")
+ end
+ end
+ end
+
+ private
+
+ def assert_encoding(encoding)
+ escapes = ["\\x00", "\\x7F", "\\x80", "\\xFF", "\\u{00}", "\\u{7F}", "\\u{80}", "\\M-\\C-?"]
+ escapes = escapes.concat(escapes.product(escapes).map(&:join))
+
+ escapes.each do |escaped|
+ source = "# encoding: #{encoding.name}\n\"#{escaped}\""
+
+ expected =
+ begin
+ eval(source).encoding
+ rescue SyntaxError => error
+ if error.message.include?("UTF-8 mixed within")
+ error.message[/UTF-8 mixed within .+? source/]
+ else
+ raise
+ end
+ end
+
+ actual =
+ Prism.parse(source).then do |result|
+ if result.success?
+ string = result.statement
+
+ if string.forced_utf8_encoding?
+ Encoding::UTF_8
+ elsif string.forced_binary_encoding?
+ Encoding::ASCII_8BIT
+ else
+ encoding
+ end
+ else
+ error = result.errors.first
+
+ if error.message.include?("mixed")
+ error.message
+ else
+ raise error.message
+ end
+ end
+ end
+
+ assert_equal expected, actual
+ end
+ end
+ end
+end
diff --git a/test/prism/encoding/symbol_encoding_test.rb b/test/prism/encoding/symbol_encoding_test.rb
new file mode 100644
index 0000000000..20c998a58b
--- /dev/null
+++ b/test/prism/encoding/symbol_encoding_test.rb
@@ -0,0 +1,108 @@
+# frozen_string_literal: true
+
+return if RUBY_ENGINE != "ruby"
+
+require_relative "../test_helper"
+
+module Prism
+ class SymbolEncodingTest < TestCase
+ each_encoding do |encoding, _|
+ define_method(:"test_symbols_#{encoding.name}") do
+ assert_symbols(encoding)
+ end
+
+ define_method(:"test_escapes_#{encoding.name}") do
+ assert_escapes(encoding)
+ end
+ end
+
+ private
+
+ def expected_encoding(source)
+ eval(source).encoding
+ end
+
+ def actual_encoding(source, encoding)
+ result = Prism.parse(source)
+
+ if result.success?
+ symbol = result.statement
+
+ if symbol.forced_utf8_encoding?
+ Encoding::UTF_8
+ elsif symbol.forced_binary_encoding?
+ Encoding::ASCII_8BIT
+ elsif symbol.forced_us_ascii_encoding?
+ Encoding::US_ASCII
+ else
+ encoding
+ end
+ else
+ raise SyntaxError.new(result.errors.map(&:message).join("\n"))
+ end
+ end
+
+ def assert_symbols(encoding)
+ [:a, :ą, :+].each do |symbol|
+ source = "# encoding: #{encoding.name}\n#{symbol.inspect}"
+
+ expected =
+ begin
+ expected_encoding(source)
+ rescue SyntaxError => error
+ if error.message.include?("invalid multibyte")
+ "invalid multibyte"
+ else
+ raise
+ end
+ end
+
+ actual =
+ begin
+ actual_encoding(source, encoding)
+ rescue SyntaxError => error
+ if error.message.include?("invalid multibyte")
+ "invalid multibyte"
+ else
+ raise
+ end
+ end
+
+ assert_equal expected, actual
+ end
+ end
+
+ def assert_escapes(encoding)
+ escapes = ["\\x00", "\\x7F", "\\x80", "\\xFF", "\\u{00}", "\\u{7F}", "\\u{80}", "\\M-\\C-?"]
+ escapes = escapes.concat(escapes.product(escapes).map(&:join))
+
+ escapes.each do |escaped|
+ source = "# encoding: #{encoding.name}\n:\"#{escaped}\""
+
+ expected =
+ begin
+ expected_encoding(source)
+ rescue SyntaxError => error
+ if error.message.include?("UTF-8 mixed within")
+ error.message[/UTF-8 mixed within .+? source/]
+ else
+ raise
+ end
+ end
+
+ actual =
+ begin
+ actual_encoding(source, encoding)
+ rescue SyntaxError => error
+ if error.message.include?("mixed")
+ error.message.split("\n", 2).first
+ else
+ raise
+ end
+ end
+
+ assert_equal expected, actual
+ end
+ end
+ end
+end
diff --git a/test/prism/errors/1_2_3.txt b/test/prism/errors/1_2_3.txt
new file mode 100644
index 0000000000..345452911f
--- /dev/null
+++ b/test/prism/errors/1_2_3.txt
@@ -0,0 +1,11 @@
+(1, 2, 3)
+ ^ unexpected ',', expecting end-of-input
+ ^ unexpected ',', ignoring it
+ ^ expected a matching `)`
+ ^ unexpected ',', expecting end-of-input
+ ^ unexpected ',', ignoring it
+ ^ unexpected ',', expecting end-of-input
+ ^ unexpected ',', ignoring it
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
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/3.3-4.0/do_not_allow_trailing_commas_in_method_parameters.txt b/test/prism/errors/3.3-4.0/do_not_allow_trailing_commas_in_method_parameters.txt
new file mode 100644
index 0000000000..c0fec0c704
--- /dev/null
+++ b/test/prism/errors/3.3-4.0/do_not_allow_trailing_commas_in_method_parameters.txt
@@ -0,0 +1,3 @@
+def foo(a,b,c,);end
+ ^ unexpected `,` in parameters
+
diff --git a/test/prism/errors/3.3-4.0/noblock.txt b/test/prism/errors/3.3-4.0/noblock.txt
new file mode 100644
index 0000000000..07939041bb
--- /dev/null
+++ b/test/prism/errors/3.3-4.0/noblock.txt
@@ -0,0 +1,6 @@
+def foo(&nil)
+ ^~~ unexpected 'nil'; expected a `)` to close the parameters
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+end
+
diff --git a/test/prism/errors/3.3-4.0/singleton_method_with_void_value.txt b/test/prism/errors/3.3-4.0/singleton_method_with_void_value.txt
new file mode 100644
index 0000000000..2954f7ea48
--- /dev/null
+++ b/test/prism/errors/3.3-4.0/singleton_method_with_void_value.txt
@@ -0,0 +1,3 @@
+def ((return; 1)).bar; end
+ ^ cannot define singleton method for literals
+
diff --git a/test/prism/errors/3.4-4.0/void_value.txt b/test/prism/errors/3.4-4.0/void_value.txt
new file mode 100644
index 0000000000..c03139bb05
--- /dev/null
+++ b/test/prism/errors/3.4-4.0/void_value.txt
@@ -0,0 +1,18 @@
+x = begin
+ return
+ ^~~~~~ unexpected void value expression
+rescue
+ return
+else
+ return
+end
+
+x = begin
+ return
+rescue
+ "OK"
+else
+ return
+ ^~~~~~ unexpected void value expression
+end
+
diff --git a/test/prism/errors/3.4/block_args_in_array_assignment.txt b/test/prism/errors/3.4/block_args_in_array_assignment.txt
new file mode 100644
index 0000000000..71dca8452b
--- /dev/null
+++ b/test/prism/errors/3.4/block_args_in_array_assignment.txt
@@ -0,0 +1,3 @@
+matrix[5, &block] = 8
+ ^~~~~~ unexpected block arg given in index assignment; blocks are not allowed in index assignment expressions
+
diff --git a/test/prism/errors/3.4/dont_allow_return_inside_sclass_body.txt b/test/prism/errors/3.4/dont_allow_return_inside_sclass_body.txt
new file mode 100644
index 0000000000..c29fe01728
--- /dev/null
+++ b/test/prism/errors/3.4/dont_allow_return_inside_sclass_body.txt
@@ -0,0 +1,3 @@
+class << A; return; end
+ ^~~~~~ Invalid return in class/module body
+
diff --git a/test/prism/errors/3.4/it_with_ordinary_parameter.txt b/test/prism/errors/3.4/it_with_ordinary_parameter.txt
new file mode 100644
index 0000000000..ff9c4276ca
--- /dev/null
+++ b/test/prism/errors/3.4/it_with_ordinary_parameter.txt
@@ -0,0 +1,3 @@
+proc { || it }
+ ^~ 'it' is not allowed when an ordinary parameter is defined
+
diff --git a/test/prism/errors/3.4/keyword_args_in_array_assignment.txt b/test/prism/errors/3.4/keyword_args_in_array_assignment.txt
new file mode 100644
index 0000000000..e379ec0ef4
--- /dev/null
+++ b/test/prism/errors/3.4/keyword_args_in_array_assignment.txt
@@ -0,0 +1,3 @@
+matrix[5, axis: :y] = 8
+ ^~~~~~~~ unexpected keyword arg given in index assignment; keywords are not allowed in index assignment expressions
+
diff --git a/test/prism/errors/4.1/do_not_allow_trailing_commas_after_terminating_arguments.txt b/test/prism/errors/4.1/do_not_allow_trailing_commas_after_terminating_arguments.txt
new file mode 100644
index 0000000000..b3e06f4154
--- /dev/null
+++ b/test/prism/errors/4.1/do_not_allow_trailing_commas_after_terminating_arguments.txt
@@ -0,0 +1,6 @@
+def foo(a,b,...,);end
+ ^ unexpected `,` in parameters
+
+def foo(a,b,&block,);end
+ ^ unexpected `,` in parameters
+
diff --git a/test/prism/errors/4.1/end_block_exit.txt b/test/prism/errors/4.1/end_block_exit.txt
new file mode 100644
index 0000000000..a4a1e9bc2c
--- /dev/null
+++ b/test/prism/errors/4.1/end_block_exit.txt
@@ -0,0 +1,10 @@
+END {
+ break
+ ^~~~~ Invalid break
+}
+
+END {
+ next
+ ^~~~ Invalid next
+}
+
diff --git a/test/prism/errors/4.1/multiple_blocks.txt b/test/prism/errors/4.1/multiple_blocks.txt
new file mode 100644
index 0000000000..7e8433cf82
--- /dev/null
+++ b/test/prism/errors/4.1/multiple_blocks.txt
@@ -0,0 +1,12 @@
+def foo(&nil, &nil); end
+ ^ unexpected parameter order
+ ^~~~ multiple block parameters; only one block is allowed
+
+def foo(&foo, &nil); end
+ ^ unexpected parameter order
+ ^~~~ multiple block parameters; only one block is allowed
+
+def foo(&nil, &foo); end
+ ^ unexpected parameter order
+ ^~~~ multiple block parameters; only one block is allowed
+
diff --git a/test/prism/errors/4.1/singleton_method_with_void_value.txt b/test/prism/errors/4.1/singleton_method_with_void_value.txt
new file mode 100644
index 0000000000..bc6cf9c602
--- /dev/null
+++ b/test/prism/errors/4.1/singleton_method_with_void_value.txt
@@ -0,0 +1,4 @@
+def ((return; 1)).bar; end
+ ^~~~~~ unexpected void value expression
+ ^ cannot define singleton method for literals
+
diff --git a/test/prism/errors/4.1/void_value.txt b/test/prism/errors/4.1/void_value.txt
new file mode 100644
index 0000000000..a27ffd763a
--- /dev/null
+++ b/test/prism/errors/4.1/void_value.txt
@@ -0,0 +1,44 @@
+x = begin
+ return
+rescue
+ return
+else
+ return
+ ^~~~~~ unexpected void value expression
+end
+
+x = begin
+ ignored_because_else_branch
+rescue
+ return
+else
+ return
+ ^~~~~~ unexpected void value expression
+end
+
+x = case
+ when 1 then return
+ ^~~~~~ unexpected void value expression
+ else return
+end
+
+x = case 1
+ in 2 then return
+ ^~~~~~ unexpected void value expression
+ else return
+end
+
+x = begin
+ return
+ ^~~~~~ unexpected void value expression
+ "NG"
+end
+
+x = if rand < 0.5
+ return
+ ^~~~~~ unexpected void value expression
+ "NG"
+else
+ return
+end
+
diff --git a/test/prism/errors/aliasing_global_variable_with_global_number_variable.txt b/test/prism/errors/aliasing_global_variable_with_global_number_variable.txt
new file mode 100644
index 0000000000..2f40a6a328
--- /dev/null
+++ b/test/prism/errors/aliasing_global_variable_with_global_number_variable.txt
@@ -0,0 +1,3 @@
+alias $a $1
+ ^~ invalid argument being passed to `alias`; can't make alias for the number variables
+
diff --git a/test/prism/errors/aliasing_global_variable_with_non_global_variable.txt b/test/prism/errors/aliasing_global_variable_with_non_global_variable.txt
new file mode 100644
index 0000000000..b6f013bab5
--- /dev/null
+++ b/test/prism/errors/aliasing_global_variable_with_non_global_variable.txt
@@ -0,0 +1,3 @@
+alias $a b
+ ^ invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable
+
diff --git a/test/prism/errors/aliasing_non_global_variable_with_global_variable.txt b/test/prism/errors/aliasing_non_global_variable_with_global_variable.txt
new file mode 100644
index 0000000000..8863f342f0
--- /dev/null
+++ b/test/prism/errors/aliasing_non_global_variable_with_global_variable.txt
@@ -0,0 +1,3 @@
+alias a $b
+ ^~ invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable
+
diff --git a/test/prism/errors/alnum_delimiters.txt b/test/prism/errors/alnum_delimiters.txt
new file mode 100644
index 0000000000..c9ed06ae51
--- /dev/null
+++ b/test/prism/errors/alnum_delimiters.txt
@@ -0,0 +1,3 @@
+%qXfooX
+^ unknown type of %string
+
diff --git a/test/prism/errors/alnum_delimiters_2.txt b/test/prism/errors/alnum_delimiters_2.txt
new file mode 100644
index 0000000000..3f78b434d6
--- /dev/null
+++ b/test/prism/errors/alnum_delimiters_2.txt
@@ -0,0 +1,3 @@
+%QXfooX
+^ unknown type of %string
+
diff --git a/test/prism/errors/alnum_delimiters_3.txt b/test/prism/errors/alnum_delimiters_3.txt
new file mode 100644
index 0000000000..55ef8d29a5
--- /dev/null
+++ b/test/prism/errors/alnum_delimiters_3.txt
@@ -0,0 +1,3 @@
+%wXfooX
+^ unknown type of %string
+
diff --git a/test/prism/errors/alnum_delimiters_4.txt b/test/prism/errors/alnum_delimiters_4.txt
new file mode 100644
index 0000000000..603b54debd
--- /dev/null
+++ b/test/prism/errors/alnum_delimiters_4.txt
@@ -0,0 +1,3 @@
+%WxfooX
+^ unknown type of %string
+
diff --git a/test/prism/errors/alnum_delimiters_5.txt b/test/prism/errors/alnum_delimiters_5.txt
new file mode 100644
index 0000000000..31c344ea90
--- /dev/null
+++ b/test/prism/errors/alnum_delimiters_5.txt
@@ -0,0 +1,3 @@
+%iXfooX
+^ unknown type of %string
+
diff --git a/test/prism/errors/alnum_delimiters_6.txt b/test/prism/errors/alnum_delimiters_6.txt
new file mode 100644
index 0000000000..79ffbbb1b8
--- /dev/null
+++ b/test/prism/errors/alnum_delimiters_6.txt
@@ -0,0 +1,3 @@
+%IXfooX
+^ unknown type of %string
+
diff --git a/test/prism/errors/alnum_delimiters_7.txt b/test/prism/errors/alnum_delimiters_7.txt
new file mode 100644
index 0000000000..809192e031
--- /dev/null
+++ b/test/prism/errors/alnum_delimiters_7.txt
@@ -0,0 +1,3 @@
+%xXfooX
+^ unknown type of %string
+
diff --git a/test/prism/errors/alnum_delimiters_8.txt b/test/prism/errors/alnum_delimiters_8.txt
new file mode 100644
index 0000000000..abfcf119c0
--- /dev/null
+++ b/test/prism/errors/alnum_delimiters_8.txt
@@ -0,0 +1,3 @@
+%rXfooX
+^ unknown type of %string
+
diff --git a/test/prism/errors/alnum_delimiters_9.txt b/test/prism/errors/alnum_delimiters_9.txt
new file mode 100644
index 0000000000..ae56d7be4f
--- /dev/null
+++ b/test/prism/errors/alnum_delimiters_9.txt
@@ -0,0 +1,3 @@
+%sXfooX
+^ unknown type of %string
+
diff --git a/test/prism/errors/amperand_dot_after_endless_range.txt b/test/prism/errors/amperand_dot_after_endless_range.txt
new file mode 100644
index 0000000000..ab8c8ccc4d
--- /dev/null
+++ b/test/prism/errors/amperand_dot_after_endless_range.txt
@@ -0,0 +1,3 @@
+0 if true...&.abs
+ ^~ unexpected '&.'; ... is a non-associative operator
+
diff --git a/test/prism/errors/argument_after_ellipsis.txt b/test/prism/errors/argument_after_ellipsis.txt
new file mode 100644
index 0000000000..3d708648a4
--- /dev/null
+++ b/test/prism/errors/argument_after_ellipsis.txt
@@ -0,0 +1,3 @@
+def foo(...); foo(..., 1); end
+ ^ unexpected argument after `...`
+
diff --git a/test/prism/errors/argument_forwarding_only_effects_its_own_internals.txt b/test/prism/errors/argument_forwarding_only_effects_its_own_internals.txt
new file mode 100644
index 0000000000..9c3f0ae3f7
--- /dev/null
+++ b/test/prism/errors/argument_forwarding_only_effects_its_own_internals.txt
@@ -0,0 +1,3 @@
+def a(...); b(...); end; def c(x, y, z); b(...); end
+ ^~~ unexpected ... when the parent method is not forwarding
+
diff --git a/test/prism/errors/argument_forwarding_when_parent_is_not_forwarding.txt b/test/prism/errors/argument_forwarding_when_parent_is_not_forwarding.txt
new file mode 100644
index 0000000000..017ba7eec9
--- /dev/null
+++ b/test/prism/errors/argument_forwarding_when_parent_is_not_forwarding.txt
@@ -0,0 +1,3 @@
+def a(x, y, z); b(...); end
+ ^~~ unexpected ... when the parent method is not forwarding
+
diff --git a/test/prism/errors/arguments_after_block.txt b/test/prism/errors/arguments_after_block.txt
new file mode 100644
index 0000000000..c33039146f
--- /dev/null
+++ b/test/prism/errors/arguments_after_block.txt
@@ -0,0 +1,17 @@
+a(&block, foo)
+ ^ unexpected argument after a block argument
+a(&block,)
+ ^ unexpected argument after a block argument
+a.(&block,)
+ ^ unexpected argument after a block argument
+a[&block,]
+ ^ unexpected argument after a block argument
+def a(&block)
+ p(&block,)
+ ^ unexpected argument after a block argument
+ a.(&block,)
+ ^ unexpected argument after a block argument
+ a[&block,]
+ ^ unexpected argument after a block argument
+end
+
diff --git a/test/prism/errors/arguments_binding_power_for_and.txt b/test/prism/errors/arguments_binding_power_for_and.txt
new file mode 100644
index 0000000000..0585a091f4
--- /dev/null
+++ b/test/prism/errors/arguments_binding_power_for_and.txt
@@ -0,0 +1,5 @@
+foo(*bar and baz)
+ ^~~ unexpected 'and'; expected a `)` to close the arguments
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
diff --git a/test/prism/errors/arguments_invalid_comma.txt b/test/prism/errors/arguments_invalid_comma.txt
new file mode 100644
index 0000000000..4e1360580c
--- /dev/null
+++ b/test/prism/errors/arguments_invalid_comma.txt
@@ -0,0 +1,4 @@
+p(a,b
+,)
+^ invalid comma
+
diff --git a/test/prism/errors/arguments_splat_after_star_star.txt b/test/prism/errors/arguments_splat_after_star_star.txt
new file mode 100644
index 0000000000..c50c81a9a3
--- /dev/null
+++ b/test/prism/errors/arguments_splat_after_star_star.txt
@@ -0,0 +1,3 @@
+def f(*, **); p(**, *); end
+ ^ unexpected `*` splat argument after a `**` keyword splat argument
+
diff --git a/test/prism/errors/array_invalid_comma.txt b/test/prism/errors/array_invalid_comma.txt
new file mode 100644
index 0000000000..2f52a253e0
--- /dev/null
+++ b/test/prism/errors/array_invalid_comma.txt
@@ -0,0 +1,4 @@
+[a
+,]
+^ invalid comma
+
diff --git a/test/prism/errors/array_with_double_commas.txt b/test/prism/errors/array_with_double_commas.txt
new file mode 100644
index 0000000000..7c971103f6
--- /dev/null
+++ b/test/prism/errors/array_with_double_commas.txt
@@ -0,0 +1,3 @@
+[a:1,,]
+ ^ unexpected ','; expected a `]` to close the array
+
diff --git a/test/prism/errors/assign_to_numbered_parameter.txt b/test/prism/errors/assign_to_numbered_parameter.txt
new file mode 100644
index 0000000000..74cc0c4032
--- /dev/null
+++ b/test/prism/errors/assign_to_numbered_parameter.txt
@@ -0,0 +1,11 @@
+a in _1
+ ^~ _1 is reserved for numbered parameters
+a => _1
+ ^~ _1 is reserved for numbered parameters
+1 => a, _1
+ ^~ _1 is reserved for numbered parameters
+1 in a, _1
+ ^~ _1 is reserved for numbered parameters
+/(?<_1>)/ =~ a
+ ^~ _1 is reserved for numbered parameters
+
diff --git a/test/prism/errors/bad_arguments.txt b/test/prism/errors/bad_arguments.txt
new file mode 100644
index 0000000000..ea19efd3c8
--- /dev/null
+++ b/test/prism/errors/bad_arguments.txt
@@ -0,0 +1,6 @@
+def foo(A, @a, $A, @@a);end
+ ^ invalid formal argument; formal argument cannot be a constant
+ ^~ invalid formal argument; formal argument cannot be an instance variable
+ ^~ invalid formal argument; formal argument cannot be a global variable
+ ^~~ invalid formal argument; formal argument cannot be a class variable
+
diff --git a/test/prism/errors/begin_at_toplevel.txt b/test/prism/errors/begin_at_toplevel.txt
new file mode 100644
index 0000000000..ce3d3b8d00
--- /dev/null
+++ b/test/prism/errors/begin_at_toplevel.txt
@@ -0,0 +1,3 @@
+def foo; BEGIN {}; end
+ ^~~~~ BEGIN is permitted only at toplevel
+
diff --git a/test/prism/errors/binary_range_with_left_unary_range.txt b/test/prism/errors/binary_range_with_left_unary_range.txt
new file mode 100644
index 0000000000..85cf55fb80
--- /dev/null
+++ b/test/prism/errors/binary_range_with_left_unary_range.txt
@@ -0,0 +1,8 @@
+..1..
+ ^~ unexpected range operator; .. and ... are non-associative and cannot be chained
+...1..
+ ^~ unexpected range operator; .. and ... are non-associative and cannot be chained
+ ^~ unexpected ..; .. is a non-associative operator
+ ^~ unexpected .., expecting end-of-input
+ ^~ unexpected .., ignoring it
+
diff --git a/test/prism/errors/block_arg_and_block.txt b/test/prism/errors/block_arg_and_block.txt
new file mode 100644
index 0000000000..c355c40475
--- /dev/null
+++ b/test/prism/errors/block_arg_and_block.txt
@@ -0,0 +1,3 @@
+foo(&1) { }
+ ^~~ both block arg and actual block given; only one block is allowed
+
diff --git a/test/prism/errors/block_args_with_endless_def.txt b/test/prism/errors/block_args_with_endless_def.txt
new file mode 100644
index 0000000000..a7242160d2
--- /dev/null
+++ b/test/prism/errors/block_args_with_endless_def.txt
@@ -0,0 +1,5 @@
+p do |a = def f = 1; b| end
+ ^~~~~~~ unexpected endless method definition; expected a default value for a parameter
+p do |a = def f = 1| 2; b|c end
+ ^~~~~~~ unexpected endless method definition; expected a default value for a parameter
+
diff --git a/test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt b/test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt
new file mode 100644
index 0000000000..1184b38ce8
--- /dev/null
+++ b/test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt
@@ -0,0 +1,5 @@
+x.each { x end
+ ^~~ unexpected 'end', expecting end-of-input
+ ^~~ unexpected 'end', ignoring it
+ ^ expected a block beginning with `{` to end with `}`
+
diff --git a/test/prism/errors/block_pass_return_value.txt b/test/prism/errors/block_pass_return_value.txt
new file mode 100644
index 0000000000..c9d12281d9
--- /dev/null
+++ b/test/prism/errors/block_pass_return_value.txt
@@ -0,0 +1,33 @@
+return &b
+ ^ unexpected '&', expecting end-of-input
+ ^ unexpected '&', ignoring it
+
+return(&b)
+ ^ unexpected '&', ignoring it
+ ^ unexpected '&', expecting end-of-input
+ ^ unexpected '&', ignoring it
+ ^ expected a matching `)`
+ ^ unexpected '&', expecting end-of-input
+ ^ unexpected '&', ignoring it
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+return a, &b
+ ^~ block argument should not be given
+
+return(a, &b)
+ ^~ unexpected write target
+ ^ unexpected '&', expecting end-of-input
+ ^ unexpected '&', ignoring it
+ ^ expected a matching `)`
+ ^ unexpected '&', expecting end-of-input
+ ^ unexpected '&', ignoring it
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+tap { break a, &b }
+ ^~ block argument should not be given
+
+tap { next a, &b }
+ ^~ block argument should not be given
+
diff --git a/test/prism/errors/break_1.txt b/test/prism/errors/break_1.txt
new file mode 100644
index 0000000000..5d74e7bde0
--- /dev/null
+++ b/test/prism/errors/break_1.txt
@@ -0,0 +1,4 @@
+break 1,;
+ ^ unexpected ';'; expected an argument
+^~~~~~~~ Invalid break
+
diff --git a/test/prism/errors/break_1_2_3.txt b/test/prism/errors/break_1_2_3.txt
new file mode 100644
index 0000000000..817207cbfe
--- /dev/null
+++ b/test/prism/errors/break_1_2_3.txt
@@ -0,0 +1,8 @@
+break(1, 2, 3)
+ ^ unexpected ',', expecting end-of-input
+ ^ unexpected ',', ignoring it
+ ^ expected a matching `)`
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+^~~~~~~~~~~~~ Invalid break
+
diff --git a/test/prism/errors/call_with_block_and_write.txt b/test/prism/errors/call_with_block_and_write.txt
new file mode 100644
index 0000000000..f63d94770e
--- /dev/null
+++ b/test/prism/errors/call_with_block_and_write.txt
@@ -0,0 +1,4 @@
+foo {} &&= 1
+^~~~~~ unexpected write target
+ ^~~ unexpected operator after a call with a block
+
diff --git a/test/prism/errors/call_with_block_operator_write.txt b/test/prism/errors/call_with_block_operator_write.txt
new file mode 100644
index 0000000000..3c36050b34
--- /dev/null
+++ b/test/prism/errors/call_with_block_operator_write.txt
@@ -0,0 +1,4 @@
+foo {} += 1
+^~~~~~ unexpected write target
+ ^~ unexpected operator after a call with a block
+
diff --git a/test/prism/errors/call_with_block_or_write.txt b/test/prism/errors/call_with_block_or_write.txt
new file mode 100644
index 0000000000..2cced0db75
--- /dev/null
+++ b/test/prism/errors/call_with_block_or_write.txt
@@ -0,0 +1,4 @@
+foo {} ||= 1
+^~~~~~ unexpected write target
+ ^~~ unexpected operator after a call with a block
+
diff --git a/test/prism/errors/cannot_assign_to_a_reserved_numbered_parameter.txt b/test/prism/errors/cannot_assign_to_a_reserved_numbered_parameter.txt
new file mode 100644
index 0000000000..750915fb1f
--- /dev/null
+++ b/test/prism/errors/cannot_assign_to_a_reserved_numbered_parameter.txt
@@ -0,0 +1,14 @@
+begin
+ _1=:a;_2=:a;_3=:a;_4=:a;_5=:a
+ ^~ _1 is reserved for numbered parameters
+ ^~ _2 is reserved for numbered parameters
+ ^~ _3 is reserved for numbered parameters
+ ^~ _4 is reserved for numbered parameters
+ ^~ _5 is reserved for numbered parameters
+ _6=:a;_7=:a;_8=:a;_9=:a;_10=:a
+ ^~ _6 is reserved for numbered parameters
+ ^~ _7 is reserved for numbered parameters
+ ^~ _8 is reserved for numbered parameters
+ ^~ _9 is reserved for numbered parameters
+end
+
diff --git a/test/prism/errors/case_without_clauses.txt b/test/prism/errors/case_without_clauses.txt
new file mode 100644
index 0000000000..3bbbfdd97f
--- /dev/null
+++ b/test/prism/errors/case_without_clauses.txt
@@ -0,0 +1,4 @@
+case :a
+^~~~ expected a `when` or `in` clause after `case`
+end
+
diff --git a/test/prism/errors/case_without_when_clauses_errors_on_else_clause.txt b/test/prism/errors/case_without_when_clauses_errors_on_else_clause.txt
new file mode 100644
index 0000000000..c5a1179fb9
--- /dev/null
+++ b/test/prism/errors/case_without_when_clauses_errors_on_else_clause.txt
@@ -0,0 +1,5 @@
+case :a
+^~~~ expected a `when` or `in` clause after `case`
+else
+end
+
diff --git a/test/prism/errors/check_value_expression.txt b/test/prism/errors/check_value_expression.txt
new file mode 100644
index 0000000000..33a472d94c
--- /dev/null
+++ b/test/prism/errors/check_value_expression.txt
@@ -0,0 +1,20 @@
+1 => ^(return)
+ ^~~~~~ unexpected void value expression
+while true
+ 1 => ^(break)
+ ^~~~~ unexpected void value expression
+ 1 => ^(next)
+ ^~~~ unexpected void value expression
+ 1 => ^(redo)
+ ^~~~ unexpected void value expression
+ 1 => ^(retry)
+ ^~~~~ Invalid retry without rescue
+ ^~~~~ unexpected void value expression
+ 1 => ^(2 => a)
+ ^~~~~~ unexpected void value expression
+end
+1 => ^(if 1; (return) else (return) end)
+ ^~~~~~ unexpected void value expression
+1 => ^(unless 1; (return) else (return) end)
+ ^~~~~~ unexpected void value expression
+
diff --git a/test/prism/errors/class_definition_in_method_body.txt b/test/prism/errors/class_definition_in_method_body.txt
new file mode 100644
index 0000000000..fcdc5746ee
--- /dev/null
+++ b/test/prism/errors/class_definition_in_method_body.txt
@@ -0,0 +1,3 @@
+def foo;class A;end;end
+ ^~~~~ unexpected class definition in method body
+
diff --git a/test/prism/errors/class_definition_in_method_defs.txt b/test/prism/errors/class_definition_in_method_defs.txt
new file mode 100644
index 0000000000..23bee0b6fb
--- /dev/null
+++ b/test/prism/errors/class_definition_in_method_defs.txt
@@ -0,0 +1,7 @@
+def foo(bar = class A;end);end
+ ^~~~~ unexpected class definition in method body
+def foo;rescue;class A;end;end
+ ^~~~~ unexpected class definition in method body
+def foo;ensure;class A;end;end
+ ^~~~~ unexpected class definition in method body
+
diff --git a/test/prism/errors/class_name.txt b/test/prism/errors/class_name.txt
new file mode 100644
index 0000000000..8b75896ddb
--- /dev/null
+++ b/test/prism/errors/class_name.txt
@@ -0,0 +1,3 @@
+class 0.X end
+ ^~~ unexpected constant path after `class`; class/module name must be CONSTANT
+
diff --git a/test/prism/errors/command_call_in.txt b/test/prism/errors/command_call_in.txt
new file mode 100644
index 0000000000..2b7286abc3
--- /dev/null
+++ b/test/prism/errors/command_call_in.txt
@@ -0,0 +1,6 @@
+foo 1 in a
+ ^~ unexpected 'in', expecting end-of-input
+ ^~ unexpected 'in', ignoring it
+a = foo 2 in b
+ ^~ unexpected 'in', expecting end-of-input
+
diff --git a/test/prism/errors/command_call_in_2.txt b/test/prism/errors/command_call_in_2.txt
new file mode 100644
index 0000000000..6676b1acba
--- /dev/null
+++ b/test/prism/errors/command_call_in_2.txt
@@ -0,0 +1,4 @@
+a.b x in pattern
+ ^~ unexpected 'in', expecting end-of-input
+ ^~ unexpected 'in', ignoring it
+
diff --git a/test/prism/errors/command_call_in_3.txt b/test/prism/errors/command_call_in_3.txt
new file mode 100644
index 0000000000..6fe026d7d3
--- /dev/null
+++ b/test/prism/errors/command_call_in_3.txt
@@ -0,0 +1,4 @@
+a.b x: in pattern
+ ^~ unexpected 'in', expecting end-of-input
+ ^~ unexpected 'in', ignoring it
+
diff --git a/test/prism/errors/command_call_in_4.txt b/test/prism/errors/command_call_in_4.txt
new file mode 100644
index 0000000000..045afe6498
--- /dev/null
+++ b/test/prism/errors/command_call_in_4.txt
@@ -0,0 +1,4 @@
+a.b &x in pattern
+ ^~ unexpected 'in', expecting end-of-input
+ ^~ unexpected 'in', ignoring it
+
diff --git a/test/prism/errors/command_call_in_5.txt b/test/prism/errors/command_call_in_5.txt
new file mode 100644
index 0000000000..be07287f81
--- /dev/null
+++ b/test/prism/errors/command_call_in_5.txt
@@ -0,0 +1,4 @@
+a.b *x => pattern
+ ^~ unexpected '=>', expecting end-of-input
+ ^~ unexpected '=>', ignoring it
+
diff --git a/test/prism/errors/command_call_in_6.txt b/test/prism/errors/command_call_in_6.txt
new file mode 100644
index 0000000000..470f323872
--- /dev/null
+++ b/test/prism/errors/command_call_in_6.txt
@@ -0,0 +1,4 @@
+a.b x: => pattern
+ ^~ unexpected '=>', expecting end-of-input
+ ^~ unexpected '=>', ignoring it
+
diff --git a/test/prism/errors/command_call_in_7.txt b/test/prism/errors/command_call_in_7.txt
new file mode 100644
index 0000000000..a8bea912b5
--- /dev/null
+++ b/test/prism/errors/command_call_in_7.txt
@@ -0,0 +1,4 @@
+a.b &x => pattern
+ ^~ unexpected '=>', expecting end-of-input
+ ^~ unexpected '=>', ignoring it
+
diff --git a/test/prism/errors/command_call_value_and.txt b/test/prism/errors/command_call_value_and.txt
new file mode 100644
index 0000000000..a131aa5530
--- /dev/null
+++ b/test/prism/errors/command_call_value_and.txt
@@ -0,0 +1,3 @@
+a = b c and 1
+ ^~~ unexpected 'and', expecting end-of-input
+
diff --git a/test/prism/errors/command_call_value_or.txt b/test/prism/errors/command_call_value_or.txt
new file mode 100644
index 0000000000..cc75714166
--- /dev/null
+++ b/test/prism/errors/command_call_value_or.txt
@@ -0,0 +1,3 @@
+a = b c or 1
+ ^~ unexpected 'or', expecting end-of-input
+
diff --git a/test/prism/errors/command_calls.txt b/test/prism/errors/command_calls.txt
new file mode 100644
index 0000000000..6601e5fbbc
--- /dev/null
+++ b/test/prism/errors/command_calls.txt
@@ -0,0 +1,10 @@
+[a b]
+ ^ unexpected local variable or method; expected a `,` separator for the array elements
+
+
+[
+ a b do
+ ^ unexpected local variable or method; expected a `,` separator for the array elements
+ end,
+]
+
diff --git a/test/prism/errors/command_calls_10.txt b/test/prism/errors/command_calls_10.txt
new file mode 100644
index 0000000000..f4d9f0fabc
--- /dev/null
+++ b/test/prism/errors/command_calls_10.txt
@@ -0,0 +1,3 @@
++a b
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_11.txt b/test/prism/errors/command_calls_11.txt
new file mode 100644
index 0000000000..868476c0c3
--- /dev/null
+++ b/test/prism/errors/command_calls_11.txt
@@ -0,0 +1,3 @@
+a + b c
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_12.txt b/test/prism/errors/command_calls_12.txt
new file mode 100644
index 0000000000..50c9ae88e3
--- /dev/null
+++ b/test/prism/errors/command_calls_12.txt
@@ -0,0 +1,3 @@
+a && b c
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_13.txt b/test/prism/errors/command_calls_13.txt
new file mode 100644
index 0000000000..50dc4a84a0
--- /dev/null
+++ b/test/prism/errors/command_calls_13.txt
@@ -0,0 +1,3 @@
+a =~ b c
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_14.txt b/test/prism/errors/command_calls_14.txt
new file mode 100644
index 0000000000..1b16fd3245
--- /dev/null
+++ b/test/prism/errors/command_calls_14.txt
@@ -0,0 +1,3 @@
+a = b, c d
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_15.txt b/test/prism/errors/command_calls_15.txt
new file mode 100644
index 0000000000..d2409fd002
--- /dev/null
+++ b/test/prism/errors/command_calls_15.txt
@@ -0,0 +1,3 @@
+a = *b c
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_16.txt b/test/prism/errors/command_calls_16.txt
new file mode 100644
index 0000000000..ceb07dfe30
--- /dev/null
+++ b/test/prism/errors/command_calls_16.txt
@@ -0,0 +1,3 @@
+a, b = c = d f
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_17.txt b/test/prism/errors/command_calls_17.txt
new file mode 100644
index 0000000000..a78ac0985d
--- /dev/null
+++ b/test/prism/errors/command_calls_17.txt
@@ -0,0 +1,5 @@
+a ? b c : d e
+ ^ expected a `:` after the true expression of a ternary operator
+ ^ unexpected ':', expecting end-of-input
+ ^ unexpected ':', ignoring it
+
diff --git a/test/prism/errors/command_calls_18.txt b/test/prism/errors/command_calls_18.txt
new file mode 100644
index 0000000000..393e7e0ae6
--- /dev/null
+++ b/test/prism/errors/command_calls_18.txt
@@ -0,0 +1,3 @@
+defined? a b
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_19.txt b/test/prism/errors/command_calls_19.txt
new file mode 100644
index 0000000000..e045187f1e
--- /dev/null
+++ b/test/prism/errors/command_calls_19.txt
@@ -0,0 +1,3 @@
+! ! a b
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_2.txt b/test/prism/errors/command_calls_2.txt
new file mode 100644
index 0000000000..13e10f7ebf
--- /dev/null
+++ b/test/prism/errors/command_calls_2.txt
@@ -0,0 +1,6 @@
+{a: b c}
+^ expected a `}` to close the hash literal
+ ^ unexpected local variable or method, expecting end-of-input
+ ^ unexpected '}', expecting end-of-input
+ ^ unexpected '}', ignoring it
+
diff --git a/test/prism/errors/command_calls_20.txt b/test/prism/errors/command_calls_20.txt
new file mode 100644
index 0000000000..3058ebce96
--- /dev/null
+++ b/test/prism/errors/command_calls_20.txt
@@ -0,0 +1,3 @@
+def f a = b c; end
+ ^ expected a delimiter to close the parameters
+
diff --git a/test/prism/errors/command_calls_21.txt b/test/prism/errors/command_calls_21.txt
new file mode 100644
index 0000000000..73d8f83539
--- /dev/null
+++ b/test/prism/errors/command_calls_21.txt
@@ -0,0 +1,5 @@
+def f(a = b c); end
+ ^ unexpected local variable or method; expected a `)` to close the parameters
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
diff --git a/test/prism/errors/command_calls_22.txt b/test/prism/errors/command_calls_22.txt
new file mode 100644
index 0000000000..5a234e04e8
--- /dev/null
+++ b/test/prism/errors/command_calls_22.txt
@@ -0,0 +1,3 @@
+a = b rescue c d
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_23.txt b/test/prism/errors/command_calls_23.txt
new file mode 100644
index 0000000000..db85589ffd
--- /dev/null
+++ b/test/prism/errors/command_calls_23.txt
@@ -0,0 +1,3 @@
+def a = b rescue c d
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_24.txt b/test/prism/errors/command_calls_24.txt
new file mode 100644
index 0000000000..27a32ea3bf
--- /dev/null
+++ b/test/prism/errors/command_calls_24.txt
@@ -0,0 +1,5 @@
+->a=b c{}
+ ^ expected a `do` keyword or a `{` to open the lambda block
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~ expected a lambda block beginning with `do` to end with `end`
+
diff --git a/test/prism/errors/command_calls_25.txt b/test/prism/errors/command_calls_25.txt
new file mode 100644
index 0000000000..cf04508f87
--- /dev/null
+++ b/test/prism/errors/command_calls_25.txt
@@ -0,0 +1,8 @@
+->(a=b c){}
+ ^ expected a matching `)`
+ ^ expected a `do` keyword or a `{` to open the lambda block
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~ expected a lambda block beginning with `do` to end with `end`
+
diff --git a/test/prism/errors/command_calls_26.txt b/test/prism/errors/command_calls_26.txt
new file mode 100644
index 0000000000..29ed4cb903
--- /dev/null
+++ b/test/prism/errors/command_calls_26.txt
@@ -0,0 +1,3 @@
+case; when a b; end
+ ^ expected a delimiter after the predicates of a `when` clause
+
diff --git a/test/prism/errors/command_calls_27.txt b/test/prism/errors/command_calls_27.txt
new file mode 100644
index 0000000000..8d1c3ee077
--- /dev/null
+++ b/test/prism/errors/command_calls_27.txt
@@ -0,0 +1,3 @@
+case; in a if a b; end
+^~~~ expected a predicate for a case matching statement
+
diff --git a/test/prism/errors/command_calls_28.txt b/test/prism/errors/command_calls_28.txt
new file mode 100644
index 0000000000..4bfe88d67b
--- /dev/null
+++ b/test/prism/errors/command_calls_28.txt
@@ -0,0 +1,3 @@
+case; in a unless a b; end
+^~~~ expected a predicate for a case matching statement
+
diff --git a/test/prism/errors/command_calls_29.txt b/test/prism/errors/command_calls_29.txt
new file mode 100644
index 0000000000..eae012ab44
--- /dev/null
+++ b/test/prism/errors/command_calls_29.txt
@@ -0,0 +1,3 @@
+begin; rescue a b; end
+ ^ expected a closing delimiter for the `rescue` clause
+
diff --git a/test/prism/errors/command_calls_3.txt b/test/prism/errors/command_calls_3.txt
new file mode 100644
index 0000000000..77af72b904
--- /dev/null
+++ b/test/prism/errors/command_calls_3.txt
@@ -0,0 +1,3 @@
+...a b
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_30.txt b/test/prism/errors/command_calls_30.txt
new file mode 100644
index 0000000000..48e35685cb
--- /dev/null
+++ b/test/prism/errors/command_calls_30.txt
@@ -0,0 +1,3 @@
+begin; rescue a b => c; end
+ ^ expected a closing delimiter for the `rescue` clause
+
diff --git a/test/prism/errors/command_calls_31.txt b/test/prism/errors/command_calls_31.txt
new file mode 100644
index 0000000000..e662b25444
--- /dev/null
+++ b/test/prism/errors/command_calls_31.txt
@@ -0,0 +1,17 @@
+true && not true
+ ^~~~ expected a `(` after `not`
+ ^~~~ unexpected 'true', expecting end-of-input
+
+true || not true
+ ^~~~ expected a `(` after `not`
+ ^~~~ unexpected 'true', expecting end-of-input
+
+true && not (true)
+ ^ expected a `(` immediately after `not`
+ ^ unexpected '(', expecting end-of-input
+
+true && not
+true
+^~~~ expected a `(` after `not`
+^~~~ unexpected 'true', expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_32.txt b/test/prism/errors/command_calls_32.txt
new file mode 100644
index 0000000000..14488ca335
--- /dev/null
+++ b/test/prism/errors/command_calls_32.txt
@@ -0,0 +1,19 @@
+foo && return bar
+ ^~~ unexpected local variable or method, expecting end-of-input
+
+tap { foo && break bar }
+ ^~~ unexpected local variable or method, expecting end-of-input
+
+tap { foo && next bar }
+ ^~~ unexpected local variable or method, expecting end-of-input
+
+foo && return()
+ ^ unexpected '(', expecting end-of-input
+
+foo && return(bar)
+ ^ unexpected '(', expecting end-of-input
+
+foo && return(bar, baz)
+ ^~~~~~~~~~ unexpected write target
+ ^ unexpected '(', expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_33.txt b/test/prism/errors/command_calls_33.txt
new file mode 100644
index 0000000000..13e3b35c9e
--- /dev/null
+++ b/test/prism/errors/command_calls_33.txt
@@ -0,0 +1,6 @@
+1 if foo = bar baz
+ ^~~ unexpected local variable or method, expecting end-of-input
+
+1 and foo = bar baz
+ ^~~ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_34.txt b/test/prism/errors/command_calls_34.txt
new file mode 100644
index 0000000000..bc0ea5e81c
--- /dev/null
+++ b/test/prism/errors/command_calls_34.txt
@@ -0,0 +1,31 @@
+foo(bar 1 do end, 2)
+ ^~ unexpected 'do'; expected a `)` to close the arguments
+ ^~ unexpected 'do', expecting end-of-input
+ ^~ unexpected 'do', ignoring it
+ ^~~ unexpected 'end', ignoring it
+ ^ unexpected ',', ignoring it
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+foo(bar 1 do end,)
+ ^~ unexpected 'do'; expected a `)` to close the arguments
+ ^~ unexpected 'do', expecting end-of-input
+ ^~ unexpected 'do', ignoring it
+ ^~~ unexpected 'end', ignoring it
+ ^ unexpected ',', ignoring it
+ ^ unexpected ')', ignoring it
+
+foo(1, bar 2 do end)
+ ^ unexpected integer; expected a `)` to close the arguments
+ ^ unexpected integer, expecting end-of-input
+ ^~ unexpected 'do', expecting end-of-input
+ ^~ unexpected 'do', ignoring it
+ ^~~ unexpected 'end', ignoring it
+ ^ unexpected ')', ignoring it
+
+foo(1, bar 2)
+ ^ unexpected integer; expected a `)` to close the arguments
+ ^ unexpected integer, expecting end-of-input
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
diff --git a/test/prism/errors/command_calls_35.txt b/test/prism/errors/command_calls_35.txt
new file mode 100644
index 0000000000..bd72d1be56
--- /dev/null
+++ b/test/prism/errors/command_calls_35.txt
@@ -0,0 +1,50 @@
+p(p a, x: b => value)
+ ^~ unexpected '=>'; expected a `)` to close the arguments
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+p(p a, x: => value)
+ ^~ unexpected '=>'; expected a `)` to close the arguments
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+p(p a, &block => value)
+ ^~ unexpected '=>'; expected a `)` to close the arguments
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+p(p a do end => value)
+ ^~ unexpected 'do'; expected a `)` to close the arguments
+ ^~ unexpected 'do', expecting end-of-input
+ ^~ unexpected 'do', ignoring it
+ ^~~ unexpected 'end', ignoring it
+ ^~ unexpected '=>', ignoring it
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+p(p a, *args => value)
+ ^~ unexpected '=>'; expected a `)` to close the arguments
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+p(p a, **kwargs => value)
+ ^~ unexpected '=>'; expected a `)` to close the arguments
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+p p 1, &block => 2, &block
+ ^~ unexpected '=>', expecting end-of-input
+ ^~ unexpected '=>', ignoring it
+ ^ unexpected ',', expecting end-of-input
+ ^ unexpected ',', ignoring it
+ ^ unexpected '&', ignoring it
+
+p p p 1 => 2 => 3 => 4
+ ^~ unexpected '=>', expecting end-of-input
+ ^~ unexpected '=>', ignoring it
+
+p[p a, x: b => value]
+ ^ expected a matching `]`
+ ^ unexpected ']', expecting end-of-input
+ ^ unexpected ']', ignoring it
+
diff --git a/test/prism/errors/command_calls_4.txt b/test/prism/errors/command_calls_4.txt
new file mode 100644
index 0000000000..4be14e57e4
--- /dev/null
+++ b/test/prism/errors/command_calls_4.txt
@@ -0,0 +1,3 @@
+if ...a b; end
+ ^ expected `then` or `;` or '\n'
+
diff --git a/test/prism/errors/command_calls_5.txt b/test/prism/errors/command_calls_5.txt
new file mode 100644
index 0000000000..799a6c1136
--- /dev/null
+++ b/test/prism/errors/command_calls_5.txt
@@ -0,0 +1,3 @@
+a b, c d
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_6.txt b/test/prism/errors/command_calls_6.txt
new file mode 100644
index 0000000000..6f09d36e94
--- /dev/null
+++ b/test/prism/errors/command_calls_6.txt
@@ -0,0 +1,6 @@
+a(b, c d)
+ ^ unexpected local variable or method; expected a `)` to close the arguments
+ ^ unexpected local variable or method, expecting end-of-input
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
diff --git a/test/prism/errors/command_calls_7.txt b/test/prism/errors/command_calls_7.txt
new file mode 100644
index 0000000000..b5d74209fa
--- /dev/null
+++ b/test/prism/errors/command_calls_7.txt
@@ -0,0 +1,6 @@
+a(*b c)
+ ^ unexpected local variable or method; expected a `)` to close the arguments
+ ^ unexpected local variable or method, expecting end-of-input
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
diff --git a/test/prism/errors/command_calls_8.txt b/test/prism/errors/command_calls_8.txt
new file mode 100644
index 0000000000..e574063e72
--- /dev/null
+++ b/test/prism/errors/command_calls_8.txt
@@ -0,0 +1,6 @@
+a(**b c)
+ ^ unexpected local variable or method; expected a `)` to close the arguments
+ ^ unexpected local variable or method, expecting end-of-input
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
diff --git a/test/prism/errors/command_calls_9.txt b/test/prism/errors/command_calls_9.txt
new file mode 100644
index 0000000000..69515d959c
--- /dev/null
+++ b/test/prism/errors/command_calls_9.txt
@@ -0,0 +1,6 @@
+a(&b c)
+ ^ unexpected local variable or method; expected a `)` to close the arguments
+ ^ unexpected local variable or method, expecting end-of-input
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
diff --git a/test/prism/errors/conditional_predicate_closed.txt b/test/prism/errors/conditional_predicate_closed.txt
new file mode 100644
index 0000000000..6655fd2b1c
--- /dev/null
+++ b/test/prism/errors/conditional_predicate_closed.txt
@@ -0,0 +1,6 @@
+if 0 0; elsif 0 0; end
+ ^ expected `then` or `;` or '\n'
+ ^ expected `then` or `;` or '\n'
+unless 0 0; end
+ ^ expected `then` or `;` or '\n'
+
diff --git a/test/prism/errors/constant_assignment_in_method.txt b/test/prism/errors/constant_assignment_in_method.txt
new file mode 100644
index 0000000000..1ee49bffe6
--- /dev/null
+++ b/test/prism/errors/constant_assignment_in_method.txt
@@ -0,0 +1,3 @@
+def foo();A=1;end
+ ^~~ dynamic constant assignment
+
diff --git a/test/prism/errors/constant_path_with_invalid_token_after.txt b/test/prism/errors/constant_path_with_invalid_token_after.txt
new file mode 100644
index 0000000000..acb6dba30a
--- /dev/null
+++ b/test/prism/errors/constant_path_with_invalid_token_after.txt
@@ -0,0 +1,4 @@
+A::$b
+ ^ expected a constant after the `::` operator
+ ^~ unexpected global variable, expecting end-of-input
+
diff --git a/test/prism/errors/content_after_unterminated_heredoc.txt b/test/prism/errors/content_after_unterminated_heredoc.txt
new file mode 100644
index 0000000000..c0446a8c39
--- /dev/null
+++ b/test/prism/errors/content_after_unterminated_heredoc.txt
@@ -0,0 +1,4 @@
+<<~FOO.foo
+ ^~~ unterminated heredoc; can't find string "FOO" anywhere before EOF
+ ^~~ unterminated heredoc; can't find string "FOO" anywhere before EOF
+
diff --git a/test/prism/errors/cr_without_lf_in_percent_expression.txt b/test/prism/errors/cr_without_lf_in_percent_expression.txt
new file mode 100644
index 0000000000..903f8b4b4a
--- /dev/null
+++ b/test/prism/errors/cr_without_lf_in_percent_expression.txt
@@ -0,0 +1,3 @@
+%
+ ^ unterminated string meets end of file
+
diff --git a/test/prism/errors/def_endless_do.txt b/test/prism/errors/def_endless_do.txt
new file mode 100644
index 0000000000..d66b7086da
--- /dev/null
+++ b/test/prism/errors/def_endless_do.txt
@@ -0,0 +1,6 @@
+def a = a b do 1 end
+ ^~ unexpected 'do', expecting end-of-input
+ ^~ unexpected 'do', ignoring it
+ ^~~ unexpected 'end', expecting end-of-input
+ ^~~ unexpected 'end', ignoring it
+
diff --git a/test/prism/errors/def_ivar.txt b/test/prism/errors/def_ivar.txt
new file mode 100644
index 0000000000..11620885cf
--- /dev/null
+++ b/test/prism/errors/def_ivar.txt
@@ -0,0 +1,3 @@
+def @foo; end
+ ^~~~ unexpected instance variable; expected a method name
+
diff --git a/test/prism/errors/def_with_empty_expression_receiver.txt b/test/prism/errors/def_with_empty_expression_receiver.txt
new file mode 100644
index 0000000000..153fe8a1c6
--- /dev/null
+++ b/test/prism/errors/def_with_empty_expression_receiver.txt
@@ -0,0 +1,3 @@
+def ().a; end
+ ^ expected a receiver for the method definition
+
diff --git a/test/prism/errors/def_with_expression_receiver_and_no_identifier.txt b/test/prism/errors/def_with_expression_receiver_and_no_identifier.txt
new file mode 100644
index 0000000000..1aefc07f1a
--- /dev/null
+++ b/test/prism/errors/def_with_expression_receiver_and_no_identifier.txt
@@ -0,0 +1,4 @@
+def (a); end
+ ^ expected a `.` or `::` after the receiver in a method definition
+ ^ unexpected ';'; expected a method name
+
diff --git a/test/prism/errors/def_with_multiple_statements_receiver.txt b/test/prism/errors/def_with_multiple_statements_receiver.txt
new file mode 100644
index 0000000000..80c9d4c190
--- /dev/null
+++ b/test/prism/errors/def_with_multiple_statements_receiver.txt
@@ -0,0 +1,10 @@
+def (
+a
+b
+^ expected a matching `)`
+^ expected a `.` or `::` after the receiver in a method definition
+ ^ expected a delimiter to close the parameters
+).c; end
+^ unexpected ')', ignoring it
+ ^ unexpected '.', ignoring it
+
diff --git a/test/prism/errors/def_with_optional_splat.txt b/test/prism/errors/def_with_optional_splat.txt
new file mode 100644
index 0000000000..74a833ceec
--- /dev/null
+++ b/test/prism/errors/def_with_optional_splat.txt
@@ -0,0 +1,6 @@
+def foo(*bar = nil); end
+ ^ unexpected '='; expected a `)` to close the parameters
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+ ^~~ unexpected 'end', ignoring it
+
diff --git a/test/prism/errors/defined_empty.txt b/test/prism/errors/defined_empty.txt
new file mode 100644
index 0000000000..4d7ea76413
--- /dev/null
+++ b/test/prism/errors/defined_empty.txt
@@ -0,0 +1,3 @@
+defined?()
+ ^ expected an expression after `defined?`
+
diff --git a/test/prism/errors/defining_numbered_parameter.txt b/test/prism/errors/defining_numbered_parameter.txt
new file mode 100644
index 0000000000..2bf05d9563
--- /dev/null
+++ b/test/prism/errors/defining_numbered_parameter.txt
@@ -0,0 +1,3 @@
+def _1; end
+ ^~ _1 is reserved for numbered parameters
+
diff --git a/test/prism/errors/defining_numbered_parameter_2.txt b/test/prism/errors/defining_numbered_parameter_2.txt
new file mode 100644
index 0000000000..dc4739b126
--- /dev/null
+++ b/test/prism/errors/defining_numbered_parameter_2.txt
@@ -0,0 +1,3 @@
+def self._1; end
+ ^~ _1 is reserved for numbered parameters
+
diff --git a/test/prism/errors/defs_endless_method.txt b/test/prism/errors/defs_endless_method.txt
new file mode 100644
index 0000000000..80db648e62
--- /dev/null
+++ b/test/prism/errors/defs_endless_method.txt
@@ -0,0 +1,12 @@
+def f=(k,v)=1
+ ^~ invalid method name; a setter method cannot be defined in an endless method definition
+
+def obj.f=(k,v)=1
+ ^~ invalid method name; a setter method cannot be defined in an endless method definition
+
+def []=(k,v)=1
+ ^~~ invalid method name; a setter method cannot be defined in an endless method definition
+
+def obj.[]=(k,v)=1
+ ^~~ invalid method name; a setter method cannot be defined in an endless method definition
+
diff --git a/test/prism/errors/destroy_call_operator_write_arguments.txt b/test/prism/errors/destroy_call_operator_write_arguments.txt
new file mode 100644
index 0000000000..b6933d61d1
--- /dev/null
+++ b/test/prism/errors/destroy_call_operator_write_arguments.txt
@@ -0,0 +1,11 @@
+t next&&do end&=
+ ^~ unexpected 'do'; expected an expression after the operator
+ ^~~~ unexpected void value expression
+ ^~~~ unexpected void value expression
+ ^~ unexpected '&=', expecting end-of-input
+ ^~ unexpected '&=', ignoring it
+ ^~~~ Invalid next
+''while=
+ ^~~~~ expected a predicate expression for the `while` statement
+ ^ unexpected '='; target cannot be written
+
diff --git a/test/prism/errors/do_not_allow_characters_other_than_0_9_a_f_and_A_F_in_u_Unicode_character_notation.txt b/test/prism/errors/do_not_allow_characters_other_than_0_9_a_f_and_A_F_in_u_Unicode_character_notation.txt
new file mode 100644
index 0000000000..953b9589d1
--- /dev/null
+++ b/test/prism/errors/do_not_allow_characters_other_than_0_9_a_f_and_A_F_in_u_Unicode_character_notation.txt
@@ -0,0 +1,4 @@
+"\u{000z}"
+ ^ invalid Unicode escape sequence
+ ^ unterminated Unicode escape
+
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
new file mode 100644
index 0000000000..639dec3af2
--- /dev/null
+++ b/test/prism/errors/do_not_allow_forward_arguments_in_blocks.txt
@@ -0,0 +1,13 @@
+a {|...|}
+ ^~~ 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
new file mode 100644
index 0000000000..03e17683e4
--- /dev/null
+++ b/test/prism/errors/do_not_allow_forward_arguments_in_lambda_literals.txt
@@ -0,0 +1,13 @@
+->(...) {}
+ ^~~ unexpected ... in lambda argument
+
+def foo(...)
+ ->(...) {}
+ ^~~ unexpected ... in lambda argument
+end
+
+def foo
+ ->(...) {}
+ ^~~ unexpected ... in lambda argument
+end
+
diff --git a/test/prism/errors/do_not_allow_more_than_6_hexadecimal_digits_in_u_Unicode_character_notation.txt b/test/prism/errors/do_not_allow_more_than_6_hexadecimal_digits_in_u_Unicode_character_notation.txt
new file mode 100644
index 0000000000..50795c9353
--- /dev/null
+++ b/test/prism/errors/do_not_allow_more_than_6_hexadecimal_digits_in_u_Unicode_character_notation.txt
@@ -0,0 +1,3 @@
+"\u{0000001}"
+ ^~~~~~~ invalid Unicode escape sequence; maximum length is 6 digits
+
diff --git a/test/prism/errors/do_not_allow_multiple_codepoints_in_a_single_character_literal.txt b/test/prism/errors/do_not_allow_multiple_codepoints_in_a_single_character_literal.txt
new file mode 100644
index 0000000000..1a93dc6c69
--- /dev/null
+++ b/test/prism/errors/do_not_allow_multiple_codepoints_in_a_single_character_literal.txt
@@ -0,0 +1,3 @@
+?\u{0001 0002}
+ ^~~ invalid Unicode escape sequence; Multiple codepoints at single character literal are disallowed
+
diff --git a/test/prism/errors/do_not_allow_trailing_commas_in_lambda_parameters.txt b/test/prism/errors/do_not_allow_trailing_commas_in_lambda_parameters.txt
new file mode 100644
index 0000000000..11f23f0345
--- /dev/null
+++ b/test/prism/errors/do_not_allow_trailing_commas_in_lambda_parameters.txt
@@ -0,0 +1,3 @@
+-> (a, b, ) {}
+ ^ unexpected `,` in parameters
+
diff --git a/test/prism/errors/dont_allow_return_inside_class_body.txt b/test/prism/errors/dont_allow_return_inside_class_body.txt
new file mode 100644
index 0000000000..286eba2103
--- /dev/null
+++ b/test/prism/errors/dont_allow_return_inside_class_body.txt
@@ -0,0 +1,3 @@
+class A; return; end
+ ^~~~~~ Invalid return in class/module body
+
diff --git a/test/prism/errors/dont_allow_return_inside_module_body.txt b/test/prism/errors/dont_allow_return_inside_module_body.txt
new file mode 100644
index 0000000000..85dd619a93
--- /dev/null
+++ b/test/prism/errors/dont_allow_return_inside_module_body.txt
@@ -0,0 +1,3 @@
+module A; return; end
+ ^~~~~~ Invalid return in class/module body
+
diff --git a/test/prism/errors/dont_allow_setting_to_back_and_nth_reference.txt b/test/prism/errors/dont_allow_setting_to_back_and_nth_reference.txt
new file mode 100644
index 0000000000..71b5b94589
--- /dev/null
+++ b/test/prism/errors/dont_allow_setting_to_back_and_nth_reference.txt
@@ -0,0 +1,7 @@
+begin
+$+ = nil
+^~ Can't set variable $+
+$1466 = nil
+^~~~~ Can't set variable $1466
+end
+
diff --git a/test/prism/errors/double_arguments_forwarding.txt b/test/prism/errors/double_arguments_forwarding.txt
new file mode 100644
index 0000000000..29c78f8c80
--- /dev/null
+++ b/test/prism/errors/double_arguments_forwarding.txt
@@ -0,0 +1,4 @@
+def foo(..., ...)
+ ^~~ unexpected parameter order
+end
+
diff --git a/test/prism/errors/double_scope_numbered_parameters.txt b/test/prism/errors/double_scope_numbered_parameters.txt
new file mode 100644
index 0000000000..0bb9df4ede
--- /dev/null
+++ b/test/prism/errors/double_scope_numbered_parameters.txt
@@ -0,0 +1,3 @@
+-> { _1 + -> { _2 } }
+ ^~ numbered parameter is already used in outer block
+
diff --git a/test/prism/errors/double_scope_repeated_numbered_parameters.txt b/test/prism/errors/double_scope_repeated_numbered_parameters.txt
new file mode 100644
index 0000000000..7b7b85a847
--- /dev/null
+++ b/test/prism/errors/double_scope_repeated_numbered_parameters.txt
@@ -0,0 +1,3 @@
+-> { _1 + -> { _1 } }
+ ^~ numbered parameter is already used in outer block
+
diff --git a/test/prism/errors/double_splat_followed_by_splat_argument.txt b/test/prism/errors/double_splat_followed_by_splat_argument.txt
new file mode 100644
index 0000000000..b2aec1167e
--- /dev/null
+++ b/test/prism/errors/double_splat_followed_by_splat_argument.txt
@@ -0,0 +1,3 @@
+a(**kwargs, *args)
+ ^~~~~ unexpected `*` splat argument after a `**` keyword splat argument
+
diff --git a/test/prism/errors/double_splat_with_double_commas.txt b/test/prism/errors/double_splat_with_double_commas.txt
new file mode 100644
index 0000000000..27873b7fac
--- /dev/null
+++ b/test/prism/errors/double_splat_with_double_commas.txt
@@ -0,0 +1,3 @@
+[**a,,]
+ ^ unexpected ','; expected a `]` to close the array
+
diff --git a/test/prism/errors/duplicate_pattern_capture.txt b/test/prism/errors/duplicate_pattern_capture.txt
new file mode 100644
index 0000000000..4b48fd3118
--- /dev/null
+++ b/test/prism/errors/duplicate_pattern_capture.txt
@@ -0,0 +1,17 @@
+case (); in [a, a]; end
+ ^ duplicated variable name
+case (); in [a, *a]; end
+ ^ duplicated variable name
+case (); in {a: a, b: a}; end
+ ^ duplicated variable name
+case (); in {a: a, **a}; end
+ ^ duplicated variable name
+case (); in [a, {a:}]; end
+ ^ duplicated variable name
+case (); in [a, {a: {a: {a: [a]}}}]; end
+ ^ duplicated variable name
+case (); in a => a; end
+ ^ duplicated variable name
+case (); in [A => a, {a: b => a}]; end
+ ^ duplicated variable name
+
diff --git a/test/prism/errors/duplicate_pattern_hash_key.txt b/test/prism/errors/duplicate_pattern_hash_key.txt
new file mode 100644
index 0000000000..201b51234f
--- /dev/null
+++ b/test/prism/errors/duplicate_pattern_hash_key.txt
@@ -0,0 +1,4 @@
+case (); in {a:, a:}; end
+ ^~ duplicated key name
+ ^ duplicated variable name
+
diff --git a/test/prism/errors/duplicate_pattern_hash_key_2.txt b/test/prism/errors/duplicate_pattern_hash_key_2.txt
new file mode 100644
index 0000000000..66756c454a
--- /dev/null
+++ b/test/prism/errors/duplicate_pattern_hash_key_2.txt
@@ -0,0 +1,3 @@
+case (); in {a:1, a:2}; end
+ ^~ duplicated key name
+
diff --git a/test/prism/errors/duplicated_parameter_names.txt b/test/prism/errors/duplicated_parameter_names.txt
new file mode 100644
index 0000000000..7b82685ca3
--- /dev/null
+++ b/test/prism/errors/duplicated_parameter_names.txt
@@ -0,0 +1,3 @@
+def foo(a,b,a);end
+ ^ duplicated argument name
+
diff --git a/test/prism/errors/duplicated_parameter_names_2.txt b/test/prism/errors/duplicated_parameter_names_2.txt
new file mode 100644
index 0000000000..8396993d56
--- /dev/null
+++ b/test/prism/errors/duplicated_parameter_names_2.txt
@@ -0,0 +1,3 @@
+def foo(a,b,*a);end
+ ^ duplicated argument name
+
diff --git a/test/prism/errors/duplicated_parameter_names_3.txt b/test/prism/errors/duplicated_parameter_names_3.txt
new file mode 100644
index 0000000000..437a6623c3
--- /dev/null
+++ b/test/prism/errors/duplicated_parameter_names_3.txt
@@ -0,0 +1,3 @@
+def foo(a,b,**a);end
+ ^ duplicated argument name
+
diff --git a/test/prism/errors/duplicated_parameter_names_4.txt b/test/prism/errors/duplicated_parameter_names_4.txt
new file mode 100644
index 0000000000..a420dd8a69
--- /dev/null
+++ b/test/prism/errors/duplicated_parameter_names_4.txt
@@ -0,0 +1,3 @@
+def foo(a,b,&a);end
+ ^ duplicated argument name
+
diff --git a/test/prism/errors/duplicated_parameter_names_5.txt b/test/prism/errors/duplicated_parameter_names_5.txt
new file mode 100644
index 0000000000..694d3a668c
--- /dev/null
+++ b/test/prism/errors/duplicated_parameter_names_5.txt
@@ -0,0 +1,3 @@
+def foo(a = 1,b,*c);end
+ ^ unexpected parameter `*`
+
diff --git a/test/prism/errors/dynamic_label_pattern.txt b/test/prism/errors/dynamic_label_pattern.txt
new file mode 100644
index 0000000000..b8d1012e45
--- /dev/null
+++ b/test/prism/errors/dynamic_label_pattern.txt
@@ -0,0 +1,3 @@
+:a => 'a': | 1
+ ^ expected a pattern expression after the key
+
diff --git a/test/prism/errors/ellipsis_in_no_paren_call.txt b/test/prism/errors/ellipsis_in_no_paren_call.txt
new file mode 100644
index 0000000000..87a847d192
--- /dev/null
+++ b/test/prism/errors/ellipsis_in_no_paren_call.txt
@@ -0,0 +1,3 @@
+def foo(...); foo 1, ...; end
+ ^~~ unexpected `...` in an non-parenthesized call
+
diff --git a/test/prism/errors/endless_method_command_call.txt b/test/prism/errors/endless_method_command_call.txt
new file mode 100644
index 0000000000..e6a328c294
--- /dev/null
+++ b/test/prism/errors/endless_method_command_call.txt
@@ -0,0 +1,3 @@
+private :m, def hello = puts "Hello"
+ ^ unexpected string literal, expecting end-of-input
+
diff --git a/test/prism/errors/endless_method_command_call_parameters.txt b/test/prism/errors/endless_method_command_call_parameters.txt
new file mode 100644
index 0000000000..5dc92ce7f9
--- /dev/null
+++ b/test/prism/errors/endless_method_command_call_parameters.txt
@@ -0,0 +1,27 @@
+def f x: = 1
+ ^ could not parse the endless method parameters
+
+def f ... = 1
+ ^ could not parse the endless method parameters
+
+def f * = 1
+ ^ could not parse the endless method parameters
+
+def f ** = 1
+ ^ could not parse the endless method parameters
+
+def f & = 1
+ ^ could not parse the endless method parameters
+
+def f *a = 1
+ ^ could not parse the endless method parameters
+
+def f **a = 1
+ ^ could not parse the endless method parameters
+
+def f &a = 1
+ ^ could not parse the endless method parameters
+
+def f a, (b) = 1
+ ^ could not parse the endless method parameters
+
diff --git a/test/prism/errors/escape_unicode_curly_whitespace.txt b/test/prism/errors/escape_unicode_curly_whitespace.txt
new file mode 100644
index 0000000000..324d8a2ae5
--- /dev/null
+++ b/test/prism/errors/escape_unicode_curly_whitespace.txt
@@ -0,0 +1,5 @@
+"\u{
+ ^ invalid Unicode escape sequence
+ ^ unterminated Unicode escape
+61}"
+
diff --git a/test/prism/errors/for_loop_delimiter.txt b/test/prism/errors/for_loop_delimiter.txt
new file mode 100644
index 0000000000..07002d9d06
--- /dev/null
+++ b/test/prism/errors/for_loop_delimiter.txt
@@ -0,0 +1,3 @@
+for a in b end
+ ^~~ unexpected 'end'; expected a 'do', newline, or ';' after the 'for' loop collection
+
diff --git a/test/prism/errors/for_loops_index_missing.txt b/test/prism/errors/for_loops_index_missing.txt
new file mode 100644
index 0000000000..a57c22b044
--- /dev/null
+++ b/test/prism/errors/for_loops_index_missing.txt
@@ -0,0 +1,5 @@
+for in 1..10
+^~~ expected an index after `for`
+i
+end
+
diff --git a/test/prism/errors/for_loops_only_end.txt b/test/prism/errors/for_loops_only_end.txt
new file mode 100644
index 0000000000..a8eaf0b8ab
--- /dev/null
+++ b/test/prism/errors/for_loops_only_end.txt
@@ -0,0 +1,6 @@
+for end
+^~~ expected an index after `for`
+ ^ expected an `in` after the index in a `for` statement
+ ^ expected a collection after the `in` in a `for` statement
+ ^~~ unexpected 'end'; expected a 'do', newline, or ';' after the 'for' loop collection
+
diff --git a/test/prism/errors/forwarding_arg_after_keyword_rest.txt b/test/prism/errors/forwarding_arg_after_keyword_rest.txt
new file mode 100644
index 0000000000..86fe4aad93
--- /dev/null
+++ b/test/prism/errors/forwarding_arg_after_keyword_rest.txt
@@ -0,0 +1,3 @@
+def f(**,...);end
+ ^~~ unexpected parameter order
+
diff --git a/test/prism/errors/forwarding_arg_and_block.txt b/test/prism/errors/forwarding_arg_and_block.txt
new file mode 100644
index 0000000000..65c75a5d7c
--- /dev/null
+++ b/test/prism/errors/forwarding_arg_and_block.txt
@@ -0,0 +1,3 @@
+def foo(...) = foo(...) { }
+ ^~~ both block arg and actual block given; only one block is allowed
+
diff --git a/test/prism/errors/heredoc_percent_q_newline_delimiter.txt b/test/prism/errors/heredoc_percent_q_newline_delimiter.txt
new file mode 100644
index 0000000000..73664c071f
--- /dev/null
+++ b/test/prism/errors/heredoc_percent_q_newline_delimiter.txt
@@ -0,0 +1,11 @@
+%q
+#{<<B}
+B
+^ unexpected constant, expecting end-of-input
+
+<<A; %q
+A
+#{<<B}
+B
+^ unexpected constant, expecting end-of-input
+
diff --git a/test/prism/errors/heredoc_unterminated.txt b/test/prism/errors/heredoc_unterminated.txt
new file mode 100644
index 0000000000..56bd162998
--- /dev/null
+++ b/test/prism/errors/heredoc_unterminated.txt
@@ -0,0 +1,9 @@
+a=>{<<b
+ ^ unterminated heredoc; can't find string "b" anywhere before EOF
+ ^~~ unexpected heredoc beginning; expected a key in the hash pattern
+ ^ unterminated heredoc; can't find string "b" anywhere before EOF
+ ^~~ expected a label as the key in the hash pattern
+ ^ expected a `}` to close the pattern expression
+ ^ unexpected heredoc ending, expecting end-of-input
+ ^ unexpected heredoc ending, ignoring it
+
diff --git a/test/prism/errors/incomplete_instance_var_string.txt b/test/prism/errors/incomplete_instance_var_string.txt
new file mode 100644
index 0000000000..b28947fc0e
--- /dev/null
+++ b/test/prism/errors/incomplete_instance_var_string.txt
@@ -0,0 +1,4 @@
+%@#@@#
+ ^ '@' without identifiers is not allowed as an instance variable name
+ ^ unexpected instance variable, expecting end-of-input
+
diff --git a/test/prism/errors/index_call_with_block_and_write.txt b/test/prism/errors/index_call_with_block_and_write.txt
new file mode 100644
index 0000000000..3d92fbfea7
--- /dev/null
+++ b/test/prism/errors/index_call_with_block_and_write.txt
@@ -0,0 +1,5 @@
+foo[1] {} &&= 1
+^~~~~~~~~ unexpected write target
+ ^~~ unexpected operator after a call with arguments
+ ^~~ unexpected operator after a call with a block
+
diff --git a/test/prism/errors/index_call_with_block_operator_write.txt b/test/prism/errors/index_call_with_block_operator_write.txt
new file mode 100644
index 0000000000..96c413cd39
--- /dev/null
+++ b/test/prism/errors/index_call_with_block_operator_write.txt
@@ -0,0 +1,5 @@
+foo[1] {} += 1
+^~~~~~~~~ unexpected write target
+ ^~ unexpected operator after a call with arguments
+ ^~ unexpected operator after a call with a block
+
diff --git a/test/prism/errors/index_call_with_block_or_write.txt b/test/prism/errors/index_call_with_block_or_write.txt
new file mode 100644
index 0000000000..2d250fba06
--- /dev/null
+++ b/test/prism/errors/index_call_with_block_or_write.txt
@@ -0,0 +1,5 @@
+foo[1] {} ||= 1
+^~~~~~~~~ unexpected write target
+ ^~~ unexpected operator after a call with arguments
+ ^~~ unexpected operator after a call with a block
+
diff --git a/test/prism/errors/infix_after_label.txt b/test/prism/errors/infix_after_label.txt
new file mode 100644
index 0000000000..f02a29470f
--- /dev/null
+++ b/test/prism/errors/infix_after_label.txt
@@ -0,0 +1,6 @@
+{ 'a':.upcase => 1 }
+ ^ unexpected '.'; expected a value in the hash literal
+^ expected a `}` to close the hash literal
+ ^ unexpected '}', expecting end-of-input
+ ^ unexpected '}', ignoring it
+
diff --git a/test/prism/errors/interpolated_regular_expression_with_unknown_regexp_options.txt b/test/prism/errors/interpolated_regular_expression_with_unknown_regexp_options.txt
new file mode 100644
index 0000000000..8e78753b1c
--- /dev/null
+++ b/test/prism/errors/interpolated_regular_expression_with_unknown_regexp_options.txt
@@ -0,0 +1,3 @@
+/#{foo}/AZaz
+ ^~~~~ unknown regexp options - AZaz
+
diff --git a/test/prism/errors/interpolated_symbol_pattern_hash_key.txt b/test/prism/errors/interpolated_symbol_pattern_hash_key.txt
new file mode 100644
index 0000000000..b4532439ff
--- /dev/null
+++ b/test/prism/errors/interpolated_symbol_pattern_hash_key.txt
@@ -0,0 +1,3 @@
+case foo; in { "bar#{1}": 1 }; end
+ ^~~~~~~~~~ symbol literal with interpolation is not allowed
+
diff --git a/test/prism/errors/invalid_global_variable_write.txt b/test/prism/errors/invalid_global_variable_write.txt
new file mode 100644
index 0000000000..9d9018bcf1
--- /dev/null
+++ b/test/prism/errors/invalid_global_variable_write.txt
@@ -0,0 +1,4 @@
+$',
+^~ Can't set variable $'
+^~ unexpected write target
+
diff --git a/test/prism/errors/invalid_hex_escape.txt b/test/prism/errors/invalid_hex_escape.txt
new file mode 100644
index 0000000000..4fb847f6d2
--- /dev/null
+++ b/test/prism/errors/invalid_hex_escape.txt
@@ -0,0 +1,3 @@
+"\xx"
+ ^~ invalid hex escape sequence
+
diff --git a/test/prism/errors/invalid_multi_target.txt b/test/prism/errors/invalid_multi_target.txt
new file mode 100644
index 0000000000..9756278b0c
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target.txt
@@ -0,0 +1,3 @@
+foo,
+^~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_10.txt b/test/prism/errors/invalid_multi_target_10.txt
new file mode 100644
index 0000000000..0e87b67d36
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_10.txt
@@ -0,0 +1,3 @@
+Foo,
+^~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_11.txt b/test/prism/errors/invalid_multi_target_11.txt
new file mode 100644
index 0000000000..8185cde79e
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_11.txt
@@ -0,0 +1,3 @@
+::Foo,
+^~~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_12.txt b/test/prism/errors/invalid_multi_target_12.txt
new file mode 100644
index 0000000000..f511a8a76f
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_12.txt
@@ -0,0 +1,3 @@
+Foo::Foo,
+^~~~~~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_13.txt b/test/prism/errors/invalid_multi_target_13.txt
new file mode 100644
index 0000000000..7c9a3fb4e1
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_13.txt
@@ -0,0 +1,3 @@
+Foo::foo,
+^~~~~~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_14.txt b/test/prism/errors/invalid_multi_target_14.txt
new file mode 100644
index 0000000000..88dc08de92
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_14.txt
@@ -0,0 +1,3 @@
+foo[foo],
+^~~~~~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_15.txt b/test/prism/errors/invalid_multi_target_15.txt
new file mode 100644
index 0000000000..c140833467
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_15.txt
@@ -0,0 +1,3 @@
+(foo, bar)
+^~~~~~~~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_16.txt b/test/prism/errors/invalid_multi_target_16.txt
new file mode 100644
index 0000000000..20ea56331f
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_16.txt
@@ -0,0 +1,3 @@
+foo((foo, bar))
+ ^~~~~~~~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_17.txt b/test/prism/errors/invalid_multi_target_17.txt
new file mode 100644
index 0000000000..da1ced0c59
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_17.txt
@@ -0,0 +1,3 @@
+foo((*))
+ ^~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_18.txt b/test/prism/errors/invalid_multi_target_18.txt
new file mode 100644
index 0000000000..2beed193b4
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_18.txt
@@ -0,0 +1,3 @@
+foo(((foo, bar), *))
+ ^~~~~~~~~~~~~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_19.txt b/test/prism/errors/invalid_multi_target_19.txt
new file mode 100644
index 0000000000..b5e3e6999a
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_19.txt
@@ -0,0 +1,3 @@
+(foo, bar) + 1
+^~~~~~~~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_2.txt b/test/prism/errors/invalid_multi_target_2.txt
new file mode 100644
index 0000000000..68a7bbc305
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_2.txt
@@ -0,0 +1,3 @@
+foo = 1; foo,
+ ^~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_20.txt b/test/prism/errors/invalid_multi_target_20.txt
new file mode 100644
index 0000000000..e800bcf204
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_20.txt
@@ -0,0 +1,3 @@
+(foo, bar) in baz
+^~~~~~~~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_3.txt b/test/prism/errors/invalid_multi_target_3.txt
new file mode 100644
index 0000000000..51e6207603
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_3.txt
@@ -0,0 +1,3 @@
+foo.bar,
+^~~~~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_4.txt b/test/prism/errors/invalid_multi_target_4.txt
new file mode 100644
index 0000000000..f4c3599ffe
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_4.txt
@@ -0,0 +1,3 @@
+*foo,
+^~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_5.txt b/test/prism/errors/invalid_multi_target_5.txt
new file mode 100644
index 0000000000..5d143a3f5d
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_5.txt
@@ -0,0 +1,3 @@
+@foo,
+^~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_6.txt b/test/prism/errors/invalid_multi_target_6.txt
new file mode 100644
index 0000000000..6d15893f57
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_6.txt
@@ -0,0 +1,3 @@
+@@foo,
+^~~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_7.txt b/test/prism/errors/invalid_multi_target_7.txt
new file mode 100644
index 0000000000..451f9f0a00
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_7.txt
@@ -0,0 +1,3 @@
+$foo,
+^~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_8.txt b/test/prism/errors/invalid_multi_target_8.txt
new file mode 100644
index 0000000000..fdbe272f9a
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_8.txt
@@ -0,0 +1,4 @@
+$1,
+^~ Can't set variable $1
+^~ unexpected write target
+
diff --git a/test/prism/errors/invalid_multi_target_9.txt b/test/prism/errors/invalid_multi_target_9.txt
new file mode 100644
index 0000000000..038f355c5d
--- /dev/null
+++ b/test/prism/errors/invalid_multi_target_9.txt
@@ -0,0 +1,4 @@
+$+,
+^~ Can't set variable $+
+^~ unexpected write target
+
diff --git a/test/prism/errors/invalid_number_underscores.txt b/test/prism/errors/invalid_number_underscores.txt
new file mode 100644
index 0000000000..8fc79ed7a2
--- /dev/null
+++ b/test/prism/errors/invalid_number_underscores.txt
@@ -0,0 +1,3 @@
+1__1
+ ^ invalid underscore placement in number
+
diff --git a/test/prism/errors/invalid_number_underscores_10.txt b/test/prism/errors/invalid_number_underscores_10.txt
new file mode 100644
index 0000000000..53b0cc0719
--- /dev/null
+++ b/test/prism/errors/invalid_number_underscores_10.txt
@@ -0,0 +1,3 @@
+01_1_
+ ^ trailing '_' in number
+
diff --git a/test/prism/errors/invalid_number_underscores_11.txt b/test/prism/errors/invalid_number_underscores_11.txt
new file mode 100644
index 0000000000..469110f86f
--- /dev/null
+++ b/test/prism/errors/invalid_number_underscores_11.txt
@@ -0,0 +1,3 @@
+0d1_1_
+ ^ trailing '_' in number
+
diff --git a/test/prism/errors/invalid_number_underscores_12.txt b/test/prism/errors/invalid_number_underscores_12.txt
new file mode 100644
index 0000000000..a9b63a4b6c
--- /dev/null
+++ b/test/prism/errors/invalid_number_underscores_12.txt
@@ -0,0 +1,3 @@
+0x1_1_
+ ^ trailing '_' in number
+
diff --git a/test/prism/errors/invalid_number_underscores_2.txt b/test/prism/errors/invalid_number_underscores_2.txt
new file mode 100644
index 0000000000..2762e08790
--- /dev/null
+++ b/test/prism/errors/invalid_number_underscores_2.txt
@@ -0,0 +1,3 @@
+0b1__1
+ ^ invalid underscore placement in number
+
diff --git a/test/prism/errors/invalid_number_underscores_3.txt b/test/prism/errors/invalid_number_underscores_3.txt
new file mode 100644
index 0000000000..23f1e0b10b
--- /dev/null
+++ b/test/prism/errors/invalid_number_underscores_3.txt
@@ -0,0 +1,3 @@
+0o1__1
+ ^ invalid underscore placement in number
+
diff --git a/test/prism/errors/invalid_number_underscores_4.txt b/test/prism/errors/invalid_number_underscores_4.txt
new file mode 100644
index 0000000000..ced149752f
--- /dev/null
+++ b/test/prism/errors/invalid_number_underscores_4.txt
@@ -0,0 +1,3 @@
+01__1
+ ^ invalid underscore placement in number
+
diff --git a/test/prism/errors/invalid_number_underscores_5.txt b/test/prism/errors/invalid_number_underscores_5.txt
new file mode 100644
index 0000000000..5e3f2bf682
--- /dev/null
+++ b/test/prism/errors/invalid_number_underscores_5.txt
@@ -0,0 +1,3 @@
+0d1__1
+ ^ invalid underscore placement in number
+
diff --git a/test/prism/errors/invalid_number_underscores_6.txt b/test/prism/errors/invalid_number_underscores_6.txt
new file mode 100644
index 0000000000..225b654248
--- /dev/null
+++ b/test/prism/errors/invalid_number_underscores_6.txt
@@ -0,0 +1,3 @@
+0x1__1
+ ^ invalid underscore placement in number
+
diff --git a/test/prism/errors/invalid_number_underscores_7.txt b/test/prism/errors/invalid_number_underscores_7.txt
new file mode 100644
index 0000000000..d953b4cbc4
--- /dev/null
+++ b/test/prism/errors/invalid_number_underscores_7.txt
@@ -0,0 +1,3 @@
+1_1_
+ ^ trailing '_' in number
+
diff --git a/test/prism/errors/invalid_number_underscores_8.txt b/test/prism/errors/invalid_number_underscores_8.txt
new file mode 100644
index 0000000000..cbdcd95d8f
--- /dev/null
+++ b/test/prism/errors/invalid_number_underscores_8.txt
@@ -0,0 +1,3 @@
+0b1_1_
+ ^ trailing '_' in number
+
diff --git a/test/prism/errors/invalid_number_underscores_9.txt b/test/prism/errors/invalid_number_underscores_9.txt
new file mode 100644
index 0000000000..173282ffb2
--- /dev/null
+++ b/test/prism/errors/invalid_number_underscores_9.txt
@@ -0,0 +1,3 @@
+0o1_1_
+ ^ trailing '_' in number
+
diff --git a/test/prism/errors/invalid_operator_write_dot.txt b/test/prism/errors/invalid_operator_write_dot.txt
new file mode 100644
index 0000000000..666817e60f
--- /dev/null
+++ b/test/prism/errors/invalid_operator_write_dot.txt
@@ -0,0 +1,3 @@
+foo.+= 1
+ ^ unexpected write target
+
diff --git a/test/prism/errors/invalid_operator_write_fcall.txt b/test/prism/errors/invalid_operator_write_fcall.txt
new file mode 100644
index 0000000000..2748bf3291
--- /dev/null
+++ b/test/prism/errors/invalid_operator_write_fcall.txt
@@ -0,0 +1,3 @@
+foo! += 1
+^~~~ unexpected write target
+
diff --git a/test/prism/errors/invalid_splat.txt b/test/prism/errors/invalid_splat.txt
new file mode 100644
index 0000000000..cffd0f9879
--- /dev/null
+++ b/test/prism/errors/invalid_splat.txt
@@ -0,0 +1,4 @@
+(1
+*a)
+^~ unexpected write target
+
diff --git a/test/prism/errors/keywords_parameters_before_required_parameters.txt b/test/prism/errors/keywords_parameters_before_required_parameters.txt
new file mode 100644
index 0000000000..42d036e950
--- /dev/null
+++ b/test/prism/errors/keywords_parameters_before_required_parameters.txt
@@ -0,0 +1,4 @@
+def foo(b:, a)
+ ^ unexpected parameter order
+end
+
diff --git a/test/prism/errors/label_in_interpolated_string.txt b/test/prism/errors/label_in_interpolated_string.txt
new file mode 100644
index 0000000000..29af5310a1
--- /dev/null
+++ b/test/prism/errors/label_in_interpolated_string.txt
@@ -0,0 +1,14 @@
+case in el""Q
+^~~~ expected a predicate for a case matching statement
+ ^ expected a delimiter after the patterns of an `in` clause
+ ^ unexpected constant, expecting end-of-input
+^~~~ expected an `end` to close the `case` statement
+ !"""#{in el"":Q
+ ^~ unexpected 'in', assuming it is closing the parent 'in' clause
+ ^ expected a `}` to close the embedded expression
+ ^~ cannot parse the string part
+ ^~ cannot parse the string part
+ ^ cannot parse the string part
+ ^~~~~~~~~~~ unexpected label
+ ^~~~~~~~~~~ expected a string for concatenation
+
diff --git a/test/prism/errors/label_in_parentheses.txt b/test/prism/errors/label_in_parentheses.txt
new file mode 100644
index 0000000000..4f6e3e9e36
--- /dev/null
+++ b/test/prism/errors/label_in_parentheses.txt
@@ -0,0 +1,3 @@
+("a":)
+ ^~~~ unexpected label
+
diff --git a/test/prism/errors/loop_conditional_is_closed.txt b/test/prism/errors/loop_conditional_is_closed.txt
new file mode 100644
index 0000000000..2be1353319
--- /dev/null
+++ b/test/prism/errors/loop_conditional_is_closed.txt
@@ -0,0 +1,4 @@
+while 0 0; foo; end; until 0 0; foo; end
+ ^ expected a predicate expression for the `while` statement
+ ^ expected a predicate expression for the `until` statement
+
diff --git a/test/prism/errors/match_plus.txt b/test/prism/errors/match_plus.txt
new file mode 100644
index 0000000000..5e349a96ad
--- /dev/null
+++ b/test/prism/errors/match_plus.txt
@@ -0,0 +1,7 @@
+a in b + c
+ ^ unexpected '+', expecting end-of-input
+ ^ unexpected '+', ignoring it
+a => b + c
+ ^ unexpected '+', expecting end-of-input
+ ^ unexpected '+', ignoring it
+
diff --git a/test/prism/errors/match_predicate_after_and_with_dot_method_call.txt b/test/prism/errors/match_predicate_after_and_with_dot_method_call.txt
new file mode 100644
index 0000000000..32b77d127c
--- /dev/null
+++ b/test/prism/errors/match_predicate_after_and_with_dot_method_call.txt
@@ -0,0 +1,3 @@
+1 and 2 in 3.inspect
+ ^ unexpected '.', expecting end-of-input
+
diff --git a/test/prism/errors/match_predicate_after_and_with_opreator.txt b/test/prism/errors/match_predicate_after_and_with_opreator.txt
new file mode 100644
index 0000000000..5a0c5925ea
--- /dev/null
+++ b/test/prism/errors/match_predicate_after_and_with_opreator.txt
@@ -0,0 +1,3 @@
+1 and 2 in 3 % 4
+ ^ unexpected '%', expecting end-of-input
+
diff --git a/test/prism/errors/match_predicate_after_or_with_dot_method_call.txt b/test/prism/errors/match_predicate_after_or_with_dot_method_call.txt
new file mode 100644
index 0000000000..0a940166dc
--- /dev/null
+++ b/test/prism/errors/match_predicate_after_or_with_dot_method_call.txt
@@ -0,0 +1,3 @@
+'a' or 1 in 1.upcase
+ ^ unexpected '.', expecting end-of-input
+
diff --git a/test/prism/errors/match_predicate_after_or_with_opreator.txt b/test/prism/errors/match_predicate_after_or_with_opreator.txt
new file mode 100644
index 0000000000..8ea69e4787
--- /dev/null
+++ b/test/prism/errors/match_predicate_after_or_with_opreator.txt
@@ -0,0 +1,3 @@
+1 or 2 in 3 + 4
+ ^ unexpected '+', expecting end-of-input
+
diff --git a/test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt b/test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt
new file mode 100644
index 0000000000..f599dc476b
--- /dev/null
+++ b/test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt
@@ -0,0 +1,4 @@
+'a' rescue 2 in 3.upcase
+ ^ unexpected '.', expecting end-of-input
+ ^ unexpected '.', ignoring it
+
diff --git a/test/prism/errors/match_predicate_after_rescue_with_opreator.txt b/test/prism/errors/match_predicate_after_rescue_with_opreator.txt
new file mode 100644
index 0000000000..44a4ba8488
--- /dev/null
+++ b/test/prism/errors/match_predicate_after_rescue_with_opreator.txt
@@ -0,0 +1,4 @@
+1 rescue 2 in 3 << 4
+ ^~ unexpected <<, expecting end-of-input
+ ^~ unexpected <<, ignoring it
+
diff --git a/test/prism/errors/match_required_after_and_with_dot_method_call.txt b/test/prism/errors/match_required_after_and_with_dot_method_call.txt
new file mode 100644
index 0000000000..0ecf86bae1
--- /dev/null
+++ b/test/prism/errors/match_required_after_and_with_dot_method_call.txt
@@ -0,0 +1,3 @@
+1 and 2 => 3.inspect
+ ^ unexpected '.', expecting end-of-input
+
diff --git a/test/prism/errors/match_required_after_and_with_opreator.txt b/test/prism/errors/match_required_after_and_with_opreator.txt
new file mode 100644
index 0000000000..eafbc1f12a
--- /dev/null
+++ b/test/prism/errors/match_required_after_and_with_opreator.txt
@@ -0,0 +1,3 @@
+1 and 2 => 3 - 4
+ ^ unexpected '-', expecting end-of-input
+
diff --git a/test/prism/errors/match_required_after_or_with_dot_method_call.txt b/test/prism/errors/match_required_after_or_with_dot_method_call.txt
new file mode 100644
index 0000000000..479413250d
--- /dev/null
+++ b/test/prism/errors/match_required_after_or_with_dot_method_call.txt
@@ -0,0 +1,3 @@
+1 or 2 => 3.inspect
+ ^ unexpected '.', expecting end-of-input
+
diff --git a/test/prism/errors/match_required_after_or_with_opreator.txt b/test/prism/errors/match_required_after_or_with_opreator.txt
new file mode 100644
index 0000000000..c35f3b66e4
--- /dev/null
+++ b/test/prism/errors/match_required_after_or_with_opreator.txt
@@ -0,0 +1,3 @@
+1 or 2 => 3 ^ 4
+ ^ unexpected '^', expecting end-of-input
+
diff --git a/test/prism/errors/match_required_after_rescue_with_dot_method_call.txt b/test/prism/errors/match_required_after_rescue_with_dot_method_call.txt
new file mode 100644
index 0000000000..abcfaf094d
--- /dev/null
+++ b/test/prism/errors/match_required_after_rescue_with_dot_method_call.txt
@@ -0,0 +1,4 @@
+1 rescue 2 => 3.inspect
+ ^ unexpected '.', expecting end-of-input
+ ^ unexpected '.', ignoring it
+
diff --git a/test/prism/errors/match_required_after_rescue_with_opreator.txt b/test/prism/errors/match_required_after_rescue_with_opreator.txt
new file mode 100644
index 0000000000..5e6387ca4d
--- /dev/null
+++ b/test/prism/errors/match_required_after_rescue_with_opreator.txt
@@ -0,0 +1,4 @@
+1 rescue 2 => 3 ** 4
+ ^~ unexpected '**', expecting end-of-input
+ ^~ unexpected '**', ignoring it
+
diff --git a/test/prism/errors/method_parameters_after_arguments_forwarding.txt b/test/prism/errors/method_parameters_after_arguments_forwarding.txt
new file mode 100644
index 0000000000..ec2aefda1d
--- /dev/null
+++ b/test/prism/errors/method_parameters_after_arguments_forwarding.txt
@@ -0,0 +1,4 @@
+def foo(..., a)
+ ^ unexpected parameter order
+end
+
diff --git a/test/prism/errors/method_parameters_after_block.txt b/test/prism/errors/method_parameters_after_block.txt
new file mode 100644
index 0000000000..6e2091d5d1
--- /dev/null
+++ b/test/prism/errors/method_parameters_after_block.txt
@@ -0,0 +1,4 @@
+def foo(&block, a)
+ ^ unexpected parameter order
+end
+
diff --git a/test/prism/errors/method_with_arguments_after_anonymous_block.txt b/test/prism/errors/method_with_arguments_after_anonymous_block.txt
new file mode 100644
index 0000000000..0d986b3c01
--- /dev/null
+++ b/test/prism/errors/method_with_arguments_after_anonymous_block.txt
@@ -0,0 +1,4 @@
+def foo(&, a)
+ ^ unexpected parameter order
+end
+
diff --git a/test/prism/errors/missing_terminator_in_parentheses.txt b/test/prism/errors/missing_terminator_in_parentheses.txt
new file mode 100644
index 0000000000..af4b698f0c
--- /dev/null
+++ b/test/prism/errors/missing_terminator_in_parentheses.txt
@@ -0,0 +1,3 @@
+(0 0)
+ ^ unexpected integer, expecting end-of-input
+
diff --git a/test/prism/errors/modifier_conditional_in_predicate.txt b/test/prism/errors/modifier_conditional_in_predicate.txt
new file mode 100644
index 0000000000..5b89ee4a26
--- /dev/null
+++ b/test/prism/errors/modifier_conditional_in_predicate.txt
@@ -0,0 +1,12 @@
+if a if b then end
+ ^~ expected `then` or `;` or '\n'
+ ^~ unexpected 'if', ignoring it
+ ^~~~ unexpected 'then', expecting end-of-input
+ ^~~~ unexpected 'then', ignoring it
+
+unless a unless b then end
+ ^~~~~~ expected `then` or `;` or '\n'
+ ^~~~~~ unexpected 'unless', ignoring it
+ ^~~~ unexpected 'then', expecting end-of-input
+ ^~~~ unexpected 'then', ignoring it
+
diff --git a/test/prism/errors/module_definition_in_method_body.txt b/test/prism/errors/module_definition_in_method_body.txt
new file mode 100644
index 0000000000..59900c96dd
--- /dev/null
+++ b/test/prism/errors/module_definition_in_method_body.txt
@@ -0,0 +1,3 @@
+def foo;module A;end;end
+ ^~~~~~ unexpected module definition in method body
+
diff --git a/test/prism/errors/module_definition_in_method_body_within_block.txt b/test/prism/errors/module_definition_in_method_body_within_block.txt
new file mode 100644
index 0000000000..204be35607
--- /dev/null
+++ b/test/prism/errors/module_definition_in_method_body_within_block.txt
@@ -0,0 +1,7 @@
+def foo
+ bar do
+ module Foo;end
+ ^~~~~~ unexpected module definition in method body
+ end
+end
+
diff --git a/test/prism/errors/module_definition_in_method_defs.txt b/test/prism/errors/module_definition_in_method_defs.txt
new file mode 100644
index 0000000000..c5a6a8a2e8
--- /dev/null
+++ b/test/prism/errors/module_definition_in_method_defs.txt
@@ -0,0 +1,7 @@
+def foo(bar = module A;end);end
+ ^~~~~~ unexpected module definition in method body
+def foo;rescue;module A;end;end
+ ^~~~~~ unexpected module definition in method body
+def foo;ensure;module A;end;end
+ ^~~~~~ unexpected module definition in method body
+
diff --git a/test/prism/errors/module_name_recoverable.txt b/test/prism/errors/module_name_recoverable.txt
new file mode 100644
index 0000000000..58a28a60c5
--- /dev/null
+++ b/test/prism/errors/module_name_recoverable.txt
@@ -0,0 +1,4 @@
+module Parent module end
+ ^~~~~~ unexpected constant path after `module`; class/module name must be CONSTANT
+ ^~~ unexpected 'end', assuming it is closing the parent module definition
+
diff --git a/test/prism/errors/multi_target_parens.txt b/test/prism/errors/multi_target_parens.txt
new file mode 100644
index 0000000000..fe1b9a4b18
--- /dev/null
+++ b/test/prism/errors/multi_target_parens.txt
@@ -0,0 +1,19 @@
+( + ( * ) )
+ ^~~~~ unexpected write target
+( a ( * ) )
+ ^~~~~ unexpected write target
+( 1 + ( * ) )
+ ^~~~~ unexpected write target
+( .. ( * ) )
+ ^~~~~ unexpected write target
+( a = ( * ) )
+ ^~~~~ unexpected write target
+( * = ( * ) )
+ ^~~~~ unexpected write target
+( a if ( * ) )
+ ^~~~~ unexpected write target
+( 1; ( * ) )
+ ^~~~~ unexpected write target
+( def f() = ( * ) )
+ ^~~~~ unexpected write target
+
diff --git a/test/prism/errors/multi_target_star.txt b/test/prism/errors/multi_target_star.txt
new file mode 100644
index 0000000000..3d6d7f4286
--- /dev/null
+++ b/test/prism/errors/multi_target_star.txt
@@ -0,0 +1,17 @@
+[(*),]
+ ^~~ unexpected write target
+[1,(a,*b,(c,d)),1]
+ ^~~~~~~~~~~~ unexpected write target
+{a:(*),}
+ ^~~ unexpected write target
+[1+(*),]
+ ^~~ unexpected write target
+x=(*),1
+ ^~~ unexpected write target
+p((*),)
+ ^~~ unexpected write target
+p (*),1
+ ^~~ unexpected write target
+x = def f = (*),1
+ ^~~ unexpected write target
+
diff --git a/test/prism/errors/multiple_error_in_parameters_order.txt b/test/prism/errors/multiple_error_in_parameters_order.txt
new file mode 100644
index 0000000000..5dae0a105a
--- /dev/null
+++ b/test/prism/errors/multiple_error_in_parameters_order.txt
@@ -0,0 +1,5 @@
+def foo(**args, a, b:)
+ ^ unexpected parameter order
+ ^~ unexpected parameter order
+end
+
diff --git a/test/prism/errors/next_1.txt b/test/prism/errors/next_1.txt
new file mode 100644
index 0000000000..83ce038ebb
--- /dev/null
+++ b/test/prism/errors/next_1.txt
@@ -0,0 +1,4 @@
+next 1,;
+ ^ unexpected ';'; expected an argument
+^~~~~~~ Invalid next
+
diff --git a/test/prism/errors/next_1_2_3.txt b/test/prism/errors/next_1_2_3.txt
new file mode 100644
index 0000000000..7abe577ab3
--- /dev/null
+++ b/test/prism/errors/next_1_2_3.txt
@@ -0,0 +1,8 @@
+next(1, 2, 3)
+ ^ unexpected ',', expecting end-of-input
+ ^ unexpected ',', ignoring it
+ ^ expected a matching `)`
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+^~~~~~~~~~~~ Invalid next
+
diff --git a/test/prism/errors/non_assoc_equality.txt b/test/prism/errors/non_assoc_equality.txt
new file mode 100644
index 0000000000..9b3f137549
--- /dev/null
+++ b/test/prism/errors/non_assoc_equality.txt
@@ -0,0 +1,25 @@
+1 == 2 == 3
+ ^~ unexpected '=='; '==' is a non-associative operator
+ ^~ unexpected '==', expecting end-of-input
+ ^~ unexpected '==', ignoring it
+1 != 2 != 3
+ ^~ unexpected '!='; '!=' is a non-associative operator
+ ^~ unexpected '!=', expecting end-of-input
+ ^~ unexpected '!=', ignoring it
+1 === 2 === 3
+ ^~~ unexpected '==='; '===' is a non-associative operator
+ ^~~ unexpected '===', expecting end-of-input
+ ^~~ unexpected '===', ignoring it
+1 =~ 2 =~ 3
+ ^~ unexpected '=~'; '=~' is a non-associative operator
+ ^~ unexpected '=~', expecting end-of-input
+ ^~ unexpected '=~', ignoring it
+1 !~ 2 !~ 3
+ ^~ unexpected '!~'; '!~' is a non-associative operator
+ ^~ unexpected '!~', expecting end-of-input
+ ^~ unexpected '!~', ignoring it
+1 <=> 2 <=> 3
+ ^~~ unexpected '<=>'; '<=>' is a non-associative operator
+ ^~~ unexpected '<=>', expecting end-of-input
+ ^~~ unexpected '<=>', ignoring it
+
diff --git a/test/prism/errors/non_assoc_range.txt b/test/prism/errors/non_assoc_range.txt
new file mode 100644
index 0000000000..12eec10594
--- /dev/null
+++ b/test/prism/errors/non_assoc_range.txt
@@ -0,0 +1,5 @@
+1....2
+ ^ unexpected '.'; ... is a non-associative operator
+ ^ unexpected '.', expecting end-of-input
+ ^ unexpected '.', ignoring it
+
diff --git a/test/prism/errors/not_without_parens_assignment.txt b/test/prism/errors/not_without_parens_assignment.txt
new file mode 100644
index 0000000000..32d58efedf
--- /dev/null
+++ b/test/prism/errors/not_without_parens_assignment.txt
@@ -0,0 +1,4 @@
+x = not y
+ ^ expected a `(` after `not`
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/not_without_parens_call.txt b/test/prism/errors/not_without_parens_call.txt
new file mode 100644
index 0000000000..a778193400
--- /dev/null
+++ b/test/prism/errors/not_without_parens_call.txt
@@ -0,0 +1,7 @@
+foo(not y)
+ ^ expected a `(` after `not`
+ ^ unexpected local variable or method; expected a `)` to close the arguments
+ ^ unexpected local variable or method, expecting end-of-input
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
diff --git a/test/prism/errors/not_without_parens_command.txt b/test/prism/errors/not_without_parens_command.txt
new file mode 100644
index 0000000000..957a06f8f1
--- /dev/null
+++ b/test/prism/errors/not_without_parens_command.txt
@@ -0,0 +1,4 @@
+foo not y
+ ^ expected a `(` after `not`
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/not_without_parens_command_call.txt b/test/prism/errors/not_without_parens_command_call.txt
new file mode 100644
index 0000000000..564833c7de
--- /dev/null
+++ b/test/prism/errors/not_without_parens_command_call.txt
@@ -0,0 +1,4 @@
+a.b not y
+ ^ expected a `(` after `not`
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/not_without_parens_return.txt b/test/prism/errors/not_without_parens_return.txt
new file mode 100644
index 0000000000..1c7edb6ff1
--- /dev/null
+++ b/test/prism/errors/not_without_parens_return.txt
@@ -0,0 +1,4 @@
+return not y
+ ^ expected a `(` after `not`
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/numbered_and_write.txt b/test/prism/errors/numbered_and_write.txt
new file mode 100644
index 0000000000..f80b97b2d5
--- /dev/null
+++ b/test/prism/errors/numbered_and_write.txt
@@ -0,0 +1,3 @@
+tap { _1 &&= 1 }
+ ^~ _1 is reserved for numbered parameters
+
diff --git a/test/prism/errors/numbered_operator_write.txt b/test/prism/errors/numbered_operator_write.txt
new file mode 100644
index 0000000000..70cd58c811
--- /dev/null
+++ b/test/prism/errors/numbered_operator_write.txt
@@ -0,0 +1,3 @@
+tap { _1 += 1 }
+ ^~ _1 is reserved for numbered parameters
+
diff --git a/test/prism/errors/numbered_or_write.txt b/test/prism/errors/numbered_or_write.txt
new file mode 100644
index 0000000000..b27495498d
--- /dev/null
+++ b/test/prism/errors/numbered_or_write.txt
@@ -0,0 +1,3 @@
+tap { _1 ||= 1 }
+ ^~ _1 is reserved for numbered parameters
+
diff --git a/test/prism/errors/numbered_parameters_in_block_arguments.txt b/test/prism/errors/numbered_parameters_in_block_arguments.txt
new file mode 100644
index 0000000000..d01999c53e
--- /dev/null
+++ b/test/prism/errors/numbered_parameters_in_block_arguments.txt
@@ -0,0 +1,3 @@
+foo { |_1| }
+ ^~ _1 is reserved for numbered parameters
+
diff --git a/test/prism/errors/optional_block_parameters_with_unary_operator.txt b/test/prism/errors/optional_block_parameters_with_unary_operator.txt
new file mode 100644
index 0000000000..fd45f12648
--- /dev/null
+++ b/test/prism/errors/optional_block_parameters_with_unary_operator.txt
@@ -0,0 +1,3 @@
+foo { |a = +b| }
+ ^ unexpected '+'; unary calls are not allowed in this context
+
diff --git a/test/prism/errors/optional_block_parameters_with_unary_operator_2.txt b/test/prism/errors/optional_block_parameters_with_unary_operator_2.txt
new file mode 100644
index 0000000000..ba98f36f84
--- /dev/null
+++ b/test/prism/errors/optional_block_parameters_with_unary_operator_2.txt
@@ -0,0 +1,3 @@
+foo { |a = -b| }
+ ^ unexpected '-'; unary calls are not allowed in this context
+
diff --git a/test/prism/errors/optional_block_parameters_with_unary_operator_3.txt b/test/prism/errors/optional_block_parameters_with_unary_operator_3.txt
new file mode 100644
index 0000000000..9770059891
--- /dev/null
+++ b/test/prism/errors/optional_block_parameters_with_unary_operator_3.txt
@@ -0,0 +1,3 @@
+foo { |a = !b| }
+ ^ unexpected '!'; unary calls are not allowed in this context
+
diff --git a/test/prism/errors/optional_block_parameters_with_unary_operator_4.txt b/test/prism/errors/optional_block_parameters_with_unary_operator_4.txt
new file mode 100644
index 0000000000..9bec68d7b3
--- /dev/null
+++ b/test/prism/errors/optional_block_parameters_with_unary_operator_4.txt
@@ -0,0 +1,3 @@
+foo { |a = ~b| }
+ ^ unexpected '~'; unary calls are not allowed in this context
+
diff --git a/test/prism/errors/parameter_name_ending_with_bang_or_question_mark.txt b/test/prism/errors/parameter_name_ending_with_bang_or_question_mark.txt
new file mode 100644
index 0000000000..db4fd6928a
--- /dev/null
+++ b/test/prism/errors/parameter_name_ending_with_bang_or_question_mark.txt
@@ -0,0 +1,4 @@
+def foo(x!,y?); end
+ ^~ unexpected name for a parameter
+ ^~ unexpected name for a parameter
+
diff --git a/test/prism/errors/parameters_invalid_comma.txt b/test/prism/errors/parameters_invalid_comma.txt
new file mode 100644
index 0000000000..2d22f7ca76
--- /dev/null
+++ b/test/prism/errors/parameters_invalid_comma.txt
@@ -0,0 +1,4 @@
+def f(a
+,b);end
+^ invalid comma
+
diff --git a/test/prism/errors/pattern-capture-in-alt-array.txt b/test/prism/errors/pattern-capture-in-alt-array.txt
new file mode 100644
index 0000000000..5cb59fa328
--- /dev/null
+++ b/test/prism/errors/pattern-capture-in-alt-array.txt
@@ -0,0 +1,4 @@
+1 => [a, b] | 2
+ ^ variable capture in alternative pattern
+ ^ variable capture in alternative pattern
+
diff --git a/test/prism/errors/pattern-capture-in-alt-hash.txt b/test/prism/errors/pattern-capture-in-alt-hash.txt
new file mode 100644
index 0000000000..150b3baecc
--- /dev/null
+++ b/test/prism/errors/pattern-capture-in-alt-hash.txt
@@ -0,0 +1,3 @@
+1 => { a: b } | 2
+ ^ variable capture in alternative pattern
+
diff --git a/test/prism/errors/pattern-capture-in-alt-name.txt b/test/prism/errors/pattern-capture-in-alt-name.txt
new file mode 100644
index 0000000000..cbf2bae85f
--- /dev/null
+++ b/test/prism/errors/pattern-capture-in-alt-name.txt
@@ -0,0 +1,3 @@
+1 => (2 => b) | 2
+ ^ variable capture in alternative pattern
+
diff --git a/test/prism/errors/pattern-capture-in-alt-top.txt b/test/prism/errors/pattern-capture-in-alt-top.txt
new file mode 100644
index 0000000000..bdf3a7f637
--- /dev/null
+++ b/test/prism/errors/pattern-capture-in-alt-top.txt
@@ -0,0 +1,4 @@
+1 => a | b
+ ^ variable capture in alternative pattern
+ ^ variable capture in alternative pattern
+
diff --git a/test/prism/errors/pattern_arithmetic_expressions.txt b/test/prism/errors/pattern_arithmetic_expressions.txt
new file mode 100644
index 0000000000..cfb3650531
--- /dev/null
+++ b/test/prism/errors/pattern_arithmetic_expressions.txt
@@ -0,0 +1,3 @@
+case 1; in -1**2; end
+ ^~~~~ expected a pattern expression after the `in` keyword
+
diff --git a/test/prism/errors/pattern_match_implicit_rest.txt b/test/prism/errors/pattern_match_implicit_rest.txt
new file mode 100644
index 0000000000..8602c0add0
--- /dev/null
+++ b/test/prism/errors/pattern_match_implicit_rest.txt
@@ -0,0 +1,3 @@
+a=>b, *,
+ ^ expected a pattern expression after `,`
+
diff --git a/test/prism/errors/pattern_string_key.txt b/test/prism/errors/pattern_string_key.txt
new file mode 100644
index 0000000000..41bc1fa57b
--- /dev/null
+++ b/test/prism/errors/pattern_string_key.txt
@@ -0,0 +1,8 @@
+case:a
+^~~~ expected an `end` to close the `case` statement
+in b:"","#{}"
+ ^~~~~ expected a label after the `,` in the hash pattern
+ ^ expected a pattern expression after the key
+ ^ expected a delimiter after the patterns of an `in` clause
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+
diff --git a/test/prism/errors/pre_execution_context.txt b/test/prism/errors/pre_execution_context.txt
new file mode 100644
index 0000000000..18b11bae97
--- /dev/null
+++ b/test/prism/errors/pre_execution_context.txt
@@ -0,0 +1,4 @@
+BEGIN { 1 + }
+ ^ unexpected '}'; expected an expression after the operator
+ ^ unexpected '}', assuming it is closing the parent 'BEGIN' block
+
diff --git a/test/prism/errors/pre_execution_missing_brace.txt b/test/prism/errors/pre_execution_missing_brace.txt
new file mode 100644
index 0000000000..e51cd0732e
--- /dev/null
+++ b/test/prism/errors/pre_execution_missing_brace.txt
@@ -0,0 +1,3 @@
+BEGIN 1 }
+ ^ expected a `{` after `BEGIN`
+
diff --git a/test/prism/errors/range_and_bin_op.txt b/test/prism/errors/range_and_bin_op.txt
new file mode 100644
index 0000000000..55928c409b
--- /dev/null
+++ b/test/prism/errors/range_and_bin_op.txt
@@ -0,0 +1,5 @@
+1..2..3
+ ^~ unexpected ..; .. is a non-associative operator
+ ^~ unexpected .., expecting end-of-input
+ ^~ unexpected .., ignoring it
+
diff --git a/test/prism/errors/range_and_bin_op_2.txt b/test/prism/errors/range_and_bin_op_2.txt
new file mode 100644
index 0000000000..6ca91a26eb
--- /dev/null
+++ b/test/prism/errors/range_and_bin_op_2.txt
@@ -0,0 +1,5 @@
+1..2..
+ ^~ unexpected ..; .. is a non-associative operator
+ ^~ unexpected .., expecting end-of-input
+ ^~ unexpected .., ignoring it
+
diff --git a/test/prism/errors/range_and_bin_op_3.txt b/test/prism/errors/range_and_bin_op_3.txt
new file mode 100644
index 0000000000..34390d0776
--- /dev/null
+++ b/test/prism/errors/range_and_bin_op_3.txt
@@ -0,0 +1,3 @@
+1.. || 2
+ ^ unexpected '|'; expected an expression after the operator
+
diff --git a/test/prism/errors/range_and_bin_op_4.txt b/test/prism/errors/range_and_bin_op_4.txt
new file mode 100644
index 0000000000..ce6e79e5ff
--- /dev/null
+++ b/test/prism/errors/range_and_bin_op_4.txt
@@ -0,0 +1,5 @@
+1.. & 2
+ ^ unexpected '&'; .. is a non-associative operator
+ ^ unexpected '&', expecting end-of-input
+ ^ unexpected '&', ignoring it
+
diff --git a/test/prism/errors/range_and_bin_op_5.txt b/test/prism/errors/range_and_bin_op_5.txt
new file mode 100644
index 0000000000..4ed91e1052
--- /dev/null
+++ b/test/prism/errors/range_and_bin_op_5.txt
@@ -0,0 +1,6 @@
+1.. * 2
+ ^ unexpected *; .. is a non-associative operator
+ ^ unexpected *, expecting end-of-input
+ ^ unexpected write target
+ ^~~ unexpected write target
+
diff --git a/test/prism/errors/range_and_bin_op_6.txt b/test/prism/errors/range_and_bin_op_6.txt
new file mode 100644
index 0000000000..5cdd7a4f44
--- /dev/null
+++ b/test/prism/errors/range_and_bin_op_6.txt
@@ -0,0 +1,3 @@
+1.. / 2
+ ^ unterminated regexp meets end of file; expected a closing delimiter
+
diff --git a/test/prism/errors/range_and_bin_op_7.txt b/test/prism/errors/range_and_bin_op_7.txt
new file mode 100644
index 0000000000..3f91b5e97f
--- /dev/null
+++ b/test/prism/errors/range_and_bin_op_7.txt
@@ -0,0 +1,3 @@
+1.. % 2
+ ^ unterminated string meets end of file
+
diff --git a/test/prism/errors/range_and_bin_op_8.txt b/test/prism/errors/range_and_bin_op_8.txt
new file mode 100644
index 0000000000..afbf3719d5
--- /dev/null
+++ b/test/prism/errors/range_and_bin_op_8.txt
@@ -0,0 +1,4 @@
+1.. ** 2
+ ^~ unexpected **, expecting end-of-input
+ ^~ unexpected **, ignoring it
+
diff --git a/test/prism/errors/range_doubled.txt b/test/prism/errors/range_doubled.txt
new file mode 100644
index 0000000000..ef63d1bede
--- /dev/null
+++ b/test/prism/errors/range_doubled.txt
@@ -0,0 +1,3 @@
+p(...1...)
+ ^~~ unexpected range operator; .. and ... are non-associative and cannot be chained
+
diff --git a/test/prism/errors/rational_number_with_exponential_portion.txt b/test/prism/errors/rational_number_with_exponential_portion.txt
new file mode 100644
index 0000000000..01a03d538f
--- /dev/null
+++ b/test/prism/errors/rational_number_with_exponential_portion.txt
@@ -0,0 +1,4 @@
+1e1r; 1e1ri
+ ^ unexpected local variable or method, expecting end-of-input
+ ^~ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/regexp_unicode_too_short.txt b/test/prism/errors/regexp_unicode_too_short.txt
new file mode 100644
index 0000000000..b6504ec9f9
--- /dev/null
+++ b/test/prism/errors/regexp_unicode_too_short.txt
@@ -0,0 +1,4 @@
+/\u
+ ^~ too short escape sequence: \u
+^ unterminated regexp meets end of file; expected a closing delimiter
+
diff --git a/test/prism/errors/regular_expression_with_unknown_regexp_options.txt b/test/prism/errors/regular_expression_with_unknown_regexp_options.txt
new file mode 100644
index 0000000000..c37291ca40
--- /dev/null
+++ b/test/prism/errors/regular_expression_with_unknown_regexp_options.txt
@@ -0,0 +1,3 @@
+/foo/AZaz
+ ^~~~~ unknown regexp options - AZaz
+
diff --git a/test/prism/errors/repeated_parameter_name_in_destructured_params.txt b/test/prism/errors/repeated_parameter_name_in_destructured_params.txt
new file mode 100644
index 0000000000..766c235325
--- /dev/null
+++ b/test/prism/errors/repeated_parameter_name_in_destructured_params.txt
@@ -0,0 +1,3 @@
+def f(a, (b, (a))); end
+ ^ duplicated argument name
+
diff --git a/test/prism/errors/rescue_pattern.txt b/test/prism/errors/rescue_pattern.txt
new file mode 100644
index 0000000000..c85feb27bd
--- /dev/null
+++ b/test/prism/errors/rescue_pattern.txt
@@ -0,0 +1,4 @@
+a rescue b => c in d
+ ^~ unexpected 'in', expecting end-of-input
+ ^~ unexpected 'in', ignoring it
+
diff --git a/test/prism/errors/rest_keywords_parameters_before_required_parameters.txt b/test/prism/errors/rest_keywords_parameters_before_required_parameters.txt
new file mode 100644
index 0000000000..406f326712
--- /dev/null
+++ b/test/prism/errors/rest_keywords_parameters_before_required_parameters.txt
@@ -0,0 +1,4 @@
+def foo(**rest, b:)
+ ^~ unexpected parameter order
+end
+
diff --git a/test/prism/errors/return_1.txt b/test/prism/errors/return_1.txt
new file mode 100644
index 0000000000..ca3c3494d2
--- /dev/null
+++ b/test/prism/errors/return_1.txt
@@ -0,0 +1,3 @@
+return 1,;
+ ^ unexpected ';'; expected an argument
+
diff --git a/test/prism/errors/return_1_2_3.txt b/test/prism/errors/return_1_2_3.txt
new file mode 100644
index 0000000000..8f6dbaf194
--- /dev/null
+++ b/test/prism/errors/return_1_2_3.txt
@@ -0,0 +1,7 @@
+return(1, 2, 3)
+ ^ unexpected ',', expecting end-of-input
+ ^ unexpected ',', ignoring it
+ ^ expected a matching `)`
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
diff --git a/test/prism/errors/returning_to_optional_parameters_multiple_times.txt b/test/prism/errors/returning_to_optional_parameters_multiple_times.txt
new file mode 100644
index 0000000000..83ca731850
--- /dev/null
+++ b/test/prism/errors/returning_to_optional_parameters_multiple_times.txt
@@ -0,0 +1,4 @@
+def foo(a, b = 1, c, d = 2, e)
+ ^ unexpected parameter order
+end
+
diff --git a/test/prism/errors/semicolon_after_inheritance_operator.txt b/test/prism/errors/semicolon_after_inheritance_operator.txt
new file mode 100644
index 0000000000..6b67e6048a
--- /dev/null
+++ b/test/prism/errors/semicolon_after_inheritance_operator.txt
@@ -0,0 +1,3 @@
+class Foo < Bar end
+ ^ unexpected `end`, expecting ';' or '\n'
+
diff --git a/test/prism/errors/setter_method_cannot_be_defined_in_an_endless_method_definition.txt b/test/prism/errors/setter_method_cannot_be_defined_in_an_endless_method_definition.txt
new file mode 100644
index 0000000000..7927664f3c
--- /dev/null
+++ b/test/prism/errors/setter_method_cannot_be_defined_in_an_endless_method_definition.txt
@@ -0,0 +1,6 @@
+def a=() = 42
+ ^~ invalid method name; a setter method cannot be defined in an endless method definition
+
+def []=() = 42
+ ^~~ invalid method name; a setter method cannot be defined in an endless method definition
+
diff --git a/test/prism/errors/shadow_args_in_block.txt b/test/prism/errors/shadow_args_in_block.txt
new file mode 100644
index 0000000000..1e7d5f9cd4
--- /dev/null
+++ b/test/prism/errors/shadow_args_in_block.txt
@@ -0,0 +1,3 @@
+tap{|a;a|}
+ ^ duplicated argument name
+
diff --git a/test/prism/errors/shadow_args_in_lambda.txt b/test/prism/errors/shadow_args_in_lambda.txt
new file mode 100644
index 0000000000..7fc78d7d8f
--- /dev/null
+++ b/test/prism/errors/shadow_args_in_lambda.txt
@@ -0,0 +1,5 @@
+->a;b{}
+ ^ expected a `do` keyword or a `{` to open the lambda block
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~ expected a lambda block beginning with `do` to end with `end`
+
diff --git a/test/prism/errors/singleton_class_delimiter.txt b/test/prism/errors/singleton_class_delimiter.txt
new file mode 100644
index 0000000000..6a0232cb40
--- /dev/null
+++ b/test/prism/errors/singleton_class_delimiter.txt
@@ -0,0 +1,3 @@
+class <<self rand end
+ ^~~~ unexpected local variable or method; expected a newline or a ';' after the singleton class
+
diff --git a/test/prism/errors/singleton_method_for_literals.txt b/test/prism/errors/singleton_method_for_literals.txt
new file mode 100644
index 0000000000..ae850fca29
--- /dev/null
+++ b/test/prism/errors/singleton_method_for_literals.txt
@@ -0,0 +1,37 @@
+def (1).g; end
+ ^ cannot define singleton method for literals
+def ((a; 1)).foo; end
+ ^ cannot define singleton method for literals
+def (((1))).foo; end
+ ^ cannot define singleton method for literals
+def (__FILE__).foo; end
+ ^~~~~~~~ cannot define singleton method for literals
+def (__ENCODING__).foo; end
+ ^~~~~~~~~~~~ cannot define singleton method for literals
+def (__LINE__).foo; end
+ ^~~~~~~~ cannot define singleton method for literals
+def ("foo").foo; end
+ ^~~~~ cannot define singleton method for literals
+def (3.14).foo; end
+ ^~~~ cannot define singleton method for literals
+def (3.14i).foo; end
+ ^~~~~ cannot define singleton method for literals
+def (:foo).foo; end
+ ^~~~ cannot define singleton method for literals
+def (:'foo').foo; end
+ ^~~~~~ cannot define singleton method for literals
+def (:'f{o}').foo; end
+ ^~~~~~~ cannot define singleton method for literals
+def ('foo').foo; end
+ ^~~~~ cannot define singleton method for literals
+def ("foo").foo; end
+ ^~~~~ cannot define singleton method for literals
+def ("#{fo}o").foo; end
+ ^~~~~~~~ cannot define singleton method for literals
+def (/foo/).foo; end
+ ^~~~~ cannot define singleton method for literals
+def (/f#{oo}/).foo; end
+ ^~~~~~~~ cannot define singleton method for literals
+def ([1]).foo; end
+ ^~~ cannot define singleton method for literals
+
diff --git a/test/prism/errors/splat_argument_after_keyword_argument.txt b/test/prism/errors/splat_argument_after_keyword_argument.txt
new file mode 100644
index 0000000000..fd2dbd0003
--- /dev/null
+++ b/test/prism/errors/splat_argument_after_keyword_argument.txt
@@ -0,0 +1,3 @@
+a(foo: bar, *args)
+ ^~~~~ unexpected `*` splat argument after a `**` keyword splat argument
+
diff --git a/test/prism/errors/statement_at_non_statement.txt b/test/prism/errors/statement_at_non_statement.txt
new file mode 100644
index 0000000000..40fe7d862e
--- /dev/null
+++ b/test/prism/errors/statement_at_non_statement.txt
@@ -0,0 +1,9 @@
+foo(alias x y)
+ ^~~~~ unexpected an `alias` at a non-statement position
+foo(BEGIN { bar })
+ ^~~~~ unexpected a `BEGIN` at a non-statement position
+foo(END { bar })
+ ^~~ unexpected an `END` at a non-statement position
+foo(undef x)
+ ^~~~~ unexpected an `undef` at a non-statement position
+
diff --git a/test/prism/errors/statement_operators.txt b/test/prism/errors/statement_operators.txt
new file mode 100644
index 0000000000..04b7c57477
--- /dev/null
+++ b/test/prism/errors/statement_operators.txt
@@ -0,0 +1,25 @@
+alias x y + 1
+ ^ unexpected '+', expecting end-of-input
+ ^ unexpected '+', ignoring it
+alias x y.z
+ ^ unexpected '.', expecting end-of-input
+ ^ unexpected '.', ignoring it
+BEGIN { bar } + 1
+ ^ unexpected '+', expecting end-of-input
+ ^ unexpected '+', ignoring it
+BEGIN { bar }.z
+ ^ unexpected '.', expecting end-of-input
+ ^ unexpected '.', ignoring it
+END { bar } + 1
+ ^ unexpected '+', expecting end-of-input
+ ^ unexpected '+', ignoring it
+END { bar }.z
+ ^ unexpected '.', expecting end-of-input
+ ^ unexpected '.', ignoring it
+undef x + 1
+ ^ unexpected '+', expecting end-of-input
+ ^ unexpected '+', ignoring it
+undef x.z
+ ^ unexpected '.', expecting end-of-input
+ ^ unexpected '.', ignoring it
+
diff --git a/test/prism/errors/switching_to_named_arguments_twice.txt b/test/prism/errors/switching_to_named_arguments_twice.txt
new file mode 100644
index 0000000000..5dae0a105a
--- /dev/null
+++ b/test/prism/errors/switching_to_named_arguments_twice.txt
@@ -0,0 +1,5 @@
+def foo(**args, a, b:)
+ ^ unexpected parameter order
+ ^~ unexpected parameter order
+end
+
diff --git a/test/prism/errors/switching_to_optional_arguments_twice.txt b/test/prism/errors/switching_to_optional_arguments_twice.txt
new file mode 100644
index 0000000000..5dae0a105a
--- /dev/null
+++ b/test/prism/errors/switching_to_optional_arguments_twice.txt
@@ -0,0 +1,5 @@
+def foo(**args, a, b:)
+ ^ unexpected parameter order
+ ^~ unexpected parameter order
+end
+
diff --git a/test/prism/errors/symbol_in_hash.txt b/test/prism/errors/symbol_in_hash.txt
new file mode 100644
index 0000000000..9e687583e5
--- /dev/null
+++ b/test/prism/errors/symbol_in_hash.txt
@@ -0,0 +1,3 @@
+{x:'y':}
+ ^~~~ unexpected label
+
diff --git a/test/prism/errors/symbol_in_keyword_parameter.txt b/test/prism/errors/symbol_in_keyword_parameter.txt
new file mode 100644
index 0000000000..9df43d8c5a
--- /dev/null
+++ b/test/prism/errors/symbol_in_keyword_parameter.txt
@@ -0,0 +1,3 @@
+def foo(x:'y':); end
+ ^~~~ unexpected label
+
diff --git a/test/prism/errors/targeting_numbered_parameter.txt b/test/prism/errors/targeting_numbered_parameter.txt
new file mode 100644
index 0000000000..39c40ad7b9
--- /dev/null
+++ b/test/prism/errors/targeting_numbered_parameter.txt
@@ -0,0 +1,3 @@
+-> { _1, = 0 }
+ ^~ _1 is reserved for numbered parameters
+
diff --git a/test/prism/errors/top_level_constant_starting_with_downcased_identifier.txt b/test/prism/errors/top_level_constant_starting_with_downcased_identifier.txt
new file mode 100644
index 0000000000..b7b54dd74e
--- /dev/null
+++ b/test/prism/errors/top_level_constant_starting_with_downcased_identifier.txt
@@ -0,0 +1,4 @@
+::foo::A
+ ^ expected a constant after the `::` operator
+ ^~~ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/top_level_constant_with_downcased_identifier.txt b/test/prism/errors/top_level_constant_with_downcased_identifier.txt
new file mode 100644
index 0000000000..032bcfaebb
--- /dev/null
+++ b/test/prism/errors/top_level_constant_with_downcased_identifier.txt
@@ -0,0 +1,4 @@
+::foo
+ ^ expected a constant after the `::` operator
+ ^~~ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/trailing_comma_after_block.txt b/test/prism/errors/trailing_comma_after_block.txt
new file mode 100644
index 0000000000..d25db0efbe
--- /dev/null
+++ b/test/prism/errors/trailing_comma_after_block.txt
@@ -0,0 +1,3 @@
+p{|&,|}
+ ^ unexpected `,` in parameters
+
diff --git a/test/prism/errors/trailing_comma_in_calls.txt b/test/prism/errors/trailing_comma_in_calls.txt
new file mode 100644
index 0000000000..966d911087
--- /dev/null
+++ b/test/prism/errors/trailing_comma_in_calls.txt
@@ -0,0 +1,3 @@
+foo 1,
+ ^ unexpected end-of-input; expected an argument
+
diff --git a/test/prism/errors/unexpected_block.txt b/test/prism/errors/unexpected_block.txt
new file mode 100644
index 0000000000..2c0741cd30
--- /dev/null
+++ b/test/prism/errors/unexpected_block.txt
@@ -0,0 +1,3 @@
+def foo = yield(&:+)
+ ^~~ block argument should not be given
+
diff --git a/test/prism/errors/unterminated_W_list.txt b/test/prism/errors/unterminated_W_list.txt
new file mode 100644
index 0000000000..89cab68abb
--- /dev/null
+++ b/test/prism/errors/unterminated_W_list.txt
@@ -0,0 +1,3 @@
+%w[
+^~~ unterminated list; expected a closing delimiter for the `%w`
+
diff --git a/test/prism/errors/unterminated_argument_expression.txt b/test/prism/errors/unterminated_argument_expression.txt
new file mode 100644
index 0000000000..c250a94bec
--- /dev/null
+++ b/test/prism/errors/unterminated_argument_expression.txt
@@ -0,0 +1,5 @@
+a %
+ ^ unterminated quoted string meets end of file
+ ^ unexpected end-of-input; expected an expression after the operator
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+
diff --git a/test/prism/errors/unterminated_begin.txt b/test/prism/errors/unterminated_begin.txt
new file mode 100644
index 0000000000..2733f830c9
--- /dev/null
+++ b/test/prism/errors/unterminated_begin.txt
@@ -0,0 +1,4 @@
+begin
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~~~~ expected an `end` to close the `begin` statement
+
diff --git a/test/prism/errors/unterminated_begin_upcase.txt b/test/prism/errors/unterminated_begin_upcase.txt
new file mode 100644
index 0000000000..5512f2089e
--- /dev/null
+++ b/test/prism/errors/unterminated_begin_upcase.txt
@@ -0,0 +1,4 @@
+BEGIN {
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+ ^ expected a `}` to close the `BEGIN` statement
+
diff --git a/test/prism/errors/unterminated_block.txt b/test/prism/errors/unterminated_block.txt
new file mode 100644
index 0000000000..db6a4aa56c
--- /dev/null
+++ b/test/prism/errors/unterminated_block.txt
@@ -0,0 +1,4 @@
+foo {
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+ ^ expected a block beginning with `{` to end with `}`
+
diff --git a/test/prism/errors/unterminated_block_do_end.txt b/test/prism/errors/unterminated_block_do_end.txt
new file mode 100644
index 0000000000..0b7c64965f
--- /dev/null
+++ b/test/prism/errors/unterminated_block_do_end.txt
@@ -0,0 +1,4 @@
+foo do
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+ ^~ expected a block beginning with `do` to end with `end`
+
diff --git a/test/prism/errors/unterminated_class.txt b/test/prism/errors/unterminated_class.txt
new file mode 100644
index 0000000000..f47a3aa7df
--- /dev/null
+++ b/test/prism/errors/unterminated_class.txt
@@ -0,0 +1,4 @@
+class Foo
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~~~~ expected an `end` to close the `class` statement
+
diff --git a/test/prism/errors/unterminated_def.txt b/test/prism/errors/unterminated_def.txt
new file mode 100644
index 0000000000..a6212e3a21
--- /dev/null
+++ b/test/prism/errors/unterminated_def.txt
@@ -0,0 +1,5 @@
+def foo
+ ^ expected a delimiter to close the parameters
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~~ expected an `end` to close the `def` statement
+
diff --git a/test/prism/errors/unterminated_embdoc.txt b/test/prism/errors/unterminated_embdoc.txt
new file mode 100644
index 0000000000..1dd9ea3ac4
--- /dev/null
+++ b/test/prism/errors/unterminated_embdoc.txt
@@ -0,0 +1,3 @@
+=begin
+^~~~~~ embedded document meets end of file
+
diff --git a/test/prism/errors/unterminated_embdoc_2.txt b/test/prism/errors/unterminated_embdoc_2.txt
new file mode 100644
index 0000000000..1dd9ea3ac4
--- /dev/null
+++ b/test/prism/errors/unterminated_embdoc_2.txt
@@ -0,0 +1,3 @@
+=begin
+^~~~~~ embedded document meets end of file
+
diff --git a/test/prism/errors/unterminated_empty_string.txt b/test/prism/errors/unterminated_empty_string.txt
new file mode 100644
index 0000000000..597102f7ee
--- /dev/null
+++ b/test/prism/errors/unterminated_empty_string.txt
@@ -0,0 +1,3 @@
+"
+ ^ unterminated string meets end of file
+
diff --git a/test/prism/errors/unterminated_end_upcase.txt b/test/prism/errors/unterminated_end_upcase.txt
new file mode 100644
index 0000000000..ef01caa0ca
--- /dev/null
+++ b/test/prism/errors/unterminated_end_upcase.txt
@@ -0,0 +1,4 @@
+END {
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+ ^ expected a `}` to close the `END` statement
+
diff --git a/test/prism/errors/unterminated_for.txt b/test/prism/errors/unterminated_for.txt
new file mode 100644
index 0000000000..75978a7cae
--- /dev/null
+++ b/test/prism/errors/unterminated_for.txt
@@ -0,0 +1,5 @@
+for x in y
+ ^ unexpected end-of-input; expected a 'do', newline, or ';' after the 'for' loop collection
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~~ expected an `end` to close the `for` loop
+
diff --git a/test/prism/errors/unterminated_global_variable.txt b/test/prism/errors/unterminated_global_variable.txt
new file mode 100644
index 0000000000..ce3e960b2e
--- /dev/null
+++ b/test/prism/errors/unterminated_global_variable.txt
@@ -0,0 +1,3 @@
+$
+^ '$' without identifiers is not allowed as a global variable name
+
diff --git a/test/prism/errors/unterminated_global_variable_2.txt b/test/prism/errors/unterminated_global_variable_2.txt
new file mode 100644
index 0000000000..302293b538
--- /dev/null
+++ b/test/prism/errors/unterminated_global_variable_2.txt
@@ -0,0 +1,3 @@
+$
+^ '$' without identifiers is not allowed as a global variable name
+
diff --git a/test/prism/errors/unterminated_heredoc_and_embexpr.txt b/test/prism/errors/unterminated_heredoc_and_embexpr.txt
new file mode 100644
index 0000000000..bed7fcd24e
--- /dev/null
+++ b/test/prism/errors/unterminated_heredoc_and_embexpr.txt
@@ -0,0 +1,11 @@
+<<A+B
+ ^ unterminated heredoc; can't find string "A" anywhere before EOF
+ ^ unexpected '+', ignoring it
+ ^ unterminated heredoc; can't find string "A" anywhere before EOF
+#{C
+ ^ unexpected heredoc ending; expected an argument
+ ^ unexpected heredoc ending, expecting end-of-input
+ ^ unexpected heredoc ending, ignoring it
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^ expected a `}` to close the embedded expression
+
diff --git a/test/prism/errors/unterminated_heredoc_and_embexpr_2.txt b/test/prism/errors/unterminated_heredoc_and_embexpr_2.txt
new file mode 100644
index 0000000000..a03ff1d212
--- /dev/null
+++ b/test/prism/errors/unterminated_heredoc_and_embexpr_2.txt
@@ -0,0 +1,9 @@
+<<A+B
+ ^ unterminated heredoc; can't find string "A" anywhere before EOF
+#{C + "#{"}
+ ^ unterminated string meets end of file
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+ ^ expected a `}` to close the embedded expression
+ ^ unterminated string; expected a closing delimiter for the interpolated string
+ ^ expected a `}` to close the embedded expression
+
diff --git a/test/prism/errors/unterminated_i_list.txt b/test/prism/errors/unterminated_i_list.txt
new file mode 100644
index 0000000000..c48be9971d
--- /dev/null
+++ b/test/prism/errors/unterminated_i_list.txt
@@ -0,0 +1,3 @@
+%i[
+^~~ unterminated list; expected a closing delimiter for the `%i`
+
diff --git a/test/prism/errors/unterminated_if.txt b/test/prism/errors/unterminated_if.txt
new file mode 100644
index 0000000000..1697931773
--- /dev/null
+++ b/test/prism/errors/unterminated_if.txt
@@ -0,0 +1,5 @@
+if true
+ ^ expected `then` or `;` or '\n'
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~ expected an `end` to close the conditional clause
+
diff --git a/test/prism/errors/unterminated_if_else.txt b/test/prism/errors/unterminated_if_else.txt
new file mode 100644
index 0000000000..db7828cce8
--- /dev/null
+++ b/test/prism/errors/unterminated_if_else.txt
@@ -0,0 +1,5 @@
+if true
+^~ expected an `end` to close the `else` clause
+else
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+
diff --git a/test/prism/errors/unterminated_interpolated_string.txt b/test/prism/errors/unterminated_interpolated_string.txt
new file mode 100644
index 0000000000..e74a4c9e20
--- /dev/null
+++ b/test/prism/errors/unterminated_interpolated_string.txt
@@ -0,0 +1,3 @@
+"hello
+ ^ unterminated string meets end of file
+
diff --git a/test/prism/errors/unterminated_interpolated_symbol.txt b/test/prism/errors/unterminated_interpolated_symbol.txt
new file mode 100644
index 0000000000..faa7597280
--- /dev/null
+++ b/test/prism/errors/unterminated_interpolated_symbol.txt
@@ -0,0 +1,3 @@
+:"#
+ ^ unterminated symbol; expected a closing delimiter for the interpolated symbol
+
diff --git a/test/prism/errors/unterminated_lambda_brace.txt b/test/prism/errors/unterminated_lambda_brace.txt
new file mode 100644
index 0000000000..75474c7534
--- /dev/null
+++ b/test/prism/errors/unterminated_lambda_brace.txt
@@ -0,0 +1,4 @@
+-> {
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+ ^ expected a lambda block beginning with `{` to end with `}`
+
diff --git a/test/prism/errors/unterminated_method_parameters.txt b/test/prism/errors/unterminated_method_parameters.txt
new file mode 100644
index 0000000000..e71371ba16
--- /dev/null
+++ b/test/prism/errors/unterminated_method_parameters.txt
@@ -0,0 +1,3 @@
+foo(
+ ^ unexpected end-of-input; expected a `)` to close the arguments
+
diff --git a/test/prism/errors/unterminated_module.txt b/test/prism/errors/unterminated_module.txt
new file mode 100644
index 0000000000..4c50ba5f63
--- /dev/null
+++ b/test/prism/errors/unterminated_module.txt
@@ -0,0 +1,4 @@
+module Foo
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~~~~~ expected an `end` to close the `module` statement
+
diff --git a/test/prism/errors/unterminated_parenthesized_expression.txt b/test/prism/errors/unterminated_parenthesized_expression.txt
new file mode 100644
index 0000000000..9025eec453
--- /dev/null
+++ b/test/prism/errors/unterminated_parenthesized_expression.txt
@@ -0,0 +1,4 @@
+(1 + 2
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+ ^ expected a matching `)`
+
diff --git a/test/prism/errors/unterminated_pattern_bracket.txt b/test/prism/errors/unterminated_pattern_bracket.txt
new file mode 100644
index 0000000000..4f35cd84af
--- /dev/null
+++ b/test/prism/errors/unterminated_pattern_bracket.txt
@@ -0,0 +1,7 @@
+case x
+^~~~ expected an `end` to close the `case` statement
+in [1
+ ^ expected a `]` to close the pattern expression
+ ^ expected a delimiter after the patterns of an `in` clause
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+
diff --git a/test/prism/errors/unterminated_pattern_paren.txt b/test/prism/errors/unterminated_pattern_paren.txt
new file mode 100644
index 0000000000..426d614e61
--- /dev/null
+++ b/test/prism/errors/unterminated_pattern_paren.txt
@@ -0,0 +1,7 @@
+case x
+^~~~ expected an `end` to close the `case` statement
+in (1
+ ^ expected a `)` to close the pattern expression
+ ^ expected a delimiter after the patterns of an `in` clause
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+
diff --git a/test/prism/errors/unterminated_regular_expression.txt b/test/prism/errors/unterminated_regular_expression.txt
new file mode 100644
index 0000000000..48f3a30810
--- /dev/null
+++ b/test/prism/errors/unterminated_regular_expression.txt
@@ -0,0 +1,3 @@
+/hello
+^ unterminated regexp meets end of file; expected a closing delimiter
+
diff --git a/test/prism/errors/unterminated_regular_expression_with_heredoc.txt b/test/prism/errors/unterminated_regular_expression_with_heredoc.txt
new file mode 100644
index 0000000000..d4688d6c9e
--- /dev/null
+++ b/test/prism/errors/unterminated_regular_expression_with_heredoc.txt
@@ -0,0 +1,4 @@
+<<-END + /b
+ ^ unterminated regexp meets end of file; expected a closing delimiter
+END
+
diff --git a/test/prism/errors/unterminated_s_symbol.txt b/test/prism/errors/unterminated_s_symbol.txt
new file mode 100644
index 0000000000..0f4be932b3
--- /dev/null
+++ b/test/prism/errors/unterminated_s_symbol.txt
@@ -0,0 +1,3 @@
+%s[abc
+^~~ unterminated quoted string; expected a closing delimiter for the dynamic symbol
+
diff --git a/test/prism/errors/unterminated_string.txt b/test/prism/errors/unterminated_string.txt
new file mode 100644
index 0000000000..89c0a08b3e
--- /dev/null
+++ b/test/prism/errors/unterminated_string.txt
@@ -0,0 +1,3 @@
+'hello
+^ unterminated string meets end of file
+
diff --git a/test/prism/errors/unterminated_unicode_brackets_should_be_a_syntax_error.txt b/test/prism/errors/unterminated_unicode_brackets_should_be_a_syntax_error.txt
new file mode 100644
index 0000000000..f3ac9f29ab
--- /dev/null
+++ b/test/prism/errors/unterminated_unicode_brackets_should_be_a_syntax_error.txt
@@ -0,0 +1,3 @@
+?\u{3
+ ^~~~ invalid Unicode list: \u{3
+
diff --git a/test/prism/errors/unterminated_until.txt b/test/prism/errors/unterminated_until.txt
new file mode 100644
index 0000000000..42a0545200
--- /dev/null
+++ b/test/prism/errors/unterminated_until.txt
@@ -0,0 +1,5 @@
+until true
+ ^ expected a predicate expression for the `until` statement
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~~~~ expected an `end` to close the `until` statement
+
diff --git a/test/prism/errors/unterminated_xstring.txt b/test/prism/errors/unterminated_xstring.txt
new file mode 100644
index 0000000000..ccd529774c
--- /dev/null
+++ b/test/prism/errors/unterminated_xstring.txt
@@ -0,0 +1,3 @@
+`hello
+^ expected a closing delimiter for the `%x` or backtick string
+
diff --git a/test/prism/errors/void_value_expression_in_arguments.txt b/test/prism/errors/void_value_expression_in_arguments.txt
new file mode 100644
index 0000000000..f57aee1454
--- /dev/null
+++ b/test/prism/errors/void_value_expression_in_arguments.txt
@@ -0,0 +1,17 @@
+foo(return)
+ ^~~~~~ unexpected void value expression
+foo(1, return)
+ ^~~~~~ unexpected void value expression
+foo(*return)
+ ^~~~~~ unexpected void value expression
+foo(**return)
+ ^~~~~~ unexpected void value expression
+foo(&return)
+ ^~~~~~ unexpected void value expression
+foo(return => 1)
+ ^~~~~~ unexpected void value expression
+foo(:a => return)
+ ^~~~~~ unexpected void value expression
+foo(a: return)
+ ^~~~~~ unexpected void value expression
+
diff --git a/test/prism/errors/void_value_expression_in_array.txt b/test/prism/errors/void_value_expression_in_array.txt
new file mode 100644
index 0000000000..a0e86fb135
--- /dev/null
+++ b/test/prism/errors/void_value_expression_in_array.txt
@@ -0,0 +1,15 @@
+[return]
+ ^~~~~~ unexpected void value expression
+[1, return]
+ ^~~~~~ unexpected void value expression
+[ return => 1 ]
+ ^~~~~~ unexpected void value expression
+[ 1 => return ]
+ ^~~~~~ unexpected void value expression
+[ a: return ]
+ ^~~~~~ unexpected void value expression
+[ *return ]
+ ^~~~~~ unexpected void value expression
+[ **return ]
+ ^~~~~~ unexpected void value expression
+
diff --git a/test/prism/errors/void_value_expression_in_assignment.txt b/test/prism/errors/void_value_expression_in_assignment.txt
new file mode 100644
index 0000000000..c651d7f39e
--- /dev/null
+++ b/test/prism/errors/void_value_expression_in_assignment.txt
@@ -0,0 +1,9 @@
+a = return
+ ^~~~~~ unexpected void value expression
+a = 1, return
+ ^~~~~~ unexpected void value expression
+a, b = return, 1
+ ^~~~~~ unexpected void value expression
+a, b = 1, *return
+ ^~~~~~ unexpected void value expression
+
diff --git a/test/prism/errors/void_value_expression_in_begin_statement.txt b/test/prism/errors/void_value_expression_in_begin_statement.txt
new file mode 100644
index 0000000000..fb968a12e1
--- /dev/null
+++ b/test/prism/errors/void_value_expression_in_begin_statement.txt
@@ -0,0 +1,19 @@
+x = return 1
+ ^~~~~~~~ unexpected void value expression
+x = return, 1
+ ^~~~~~ unexpected void value expression
+x = 1, return
+ ^~~~~~ unexpected void value expression
+x, y = return
+ ^~~~~~ unexpected void value expression
+x = begin return ensure end
+ ^~~~~~ unexpected void value expression
+x = begin ensure return end
+ ^~~~~~ unexpected void value expression
+x = begin return ensure return end
+ ^~~~~~ unexpected void value expression
+x = begin return; rescue; return end
+ ^~~~~~ unexpected void value expression
+x = begin; return; rescue; retry; end
+ ^~~~~~ unexpected void value expression
+
diff --git a/test/prism/errors/void_value_expression_in_binary_call.txt b/test/prism/errors/void_value_expression_in_binary_call.txt
new file mode 100644
index 0000000000..096b42be4d
--- /dev/null
+++ b/test/prism/errors/void_value_expression_in_binary_call.txt
@@ -0,0 +1,11 @@
+1 + (return)
+ ^~~~~~ unexpected void value expression
+(return) + 1
+ ^~~~~~ unexpected void value expression
+1 and (return)
+(return) and 1
+ ^~~~~~ unexpected void value expression
+1 or (return)
+(return) or 1
+ ^~~~~~ unexpected void value expression
+
diff --git a/test/prism/errors/void_value_expression_in_call.txt b/test/prism/errors/void_value_expression_in_call.txt
new file mode 100644
index 0000000000..90e6481c4c
--- /dev/null
+++ b/test/prism/errors/void_value_expression_in_call.txt
@@ -0,0 +1,11 @@
+(return).foo
+ ^~~~~~ unexpected void value expression
+(return).(1)
+ ^~~~~~ unexpected void value expression
+(return)[1]
+ ^~~~~~ unexpected void value expression
+(return)[1] = 2
+ ^~~~~~ unexpected void value expression
+(return)::foo
+ ^~~~~~ unexpected void value expression
+
diff --git a/test/prism/errors/void_value_expression_in_constant_path.txt b/test/prism/errors/void_value_expression_in_constant_path.txt
new file mode 100644
index 0000000000..1dab6902a2
--- /dev/null
+++ b/test/prism/errors/void_value_expression_in_constant_path.txt
@@ -0,0 +1,5 @@
+(return)::A
+ ^~~~~~ unexpected void value expression
+class (return)::A; end
+ ^~~~~~ unexpected void value expression
+
diff --git a/test/prism/errors/void_value_expression_in_def.txt b/test/prism/errors/void_value_expression_in_def.txt
new file mode 100644
index 0000000000..fed52a6677
--- /dev/null
+++ b/test/prism/errors/void_value_expression_in_def.txt
@@ -0,0 +1,10 @@
+def (return).x
+ ^~~~~~ unexpected void value expression
+end
+def x(a = return)
+ ^~~~~~ unexpected void value expression
+end
+def x(a: return)
+ ^~~~~~ unexpected void value expression
+end
+
diff --git a/test/prism/errors/void_value_expression_in_expression.txt b/test/prism/errors/void_value_expression_in_expression.txt
new file mode 100644
index 0000000000..f6165a7ba6
--- /dev/null
+++ b/test/prism/errors/void_value_expression_in_expression.txt
@@ -0,0 +1,19 @@
+(return) ? 1 : 1
+ ^~~~~~ unexpected void value expression
+(return)..1
+ ^~~~~~ unexpected void value expression
+1..(return)
+ ^~~~~~ unexpected void value expression
+(return)...1
+ ^~~~~~ unexpected void value expression
+1...(return)
+ ^~~~~~ unexpected void value expression
+(..(return))
+ ^~~~~~ unexpected void value expression
+(...(return))
+ ^~~~~~ unexpected void value expression
+((return)..)
+ ^~~~~~ unexpected void value expression
+((return)...)
+ ^~~~~~ unexpected void value expression
+
diff --git a/test/prism/errors/void_value_expression_in_hash.txt b/test/prism/errors/void_value_expression_in_hash.txt
new file mode 100644
index 0000000000..7795511443
--- /dev/null
+++ b/test/prism/errors/void_value_expression_in_hash.txt
@@ -0,0 +1,9 @@
+{ return => 1 }
+ ^~~~~~ unexpected void value expression
+{ 1 => return }
+ ^~~~~~ unexpected void value expression
+{ a: return }
+ ^~~~~~ unexpected void value expression
+{ **return }
+ ^~~~~~ unexpected void value expression
+
diff --git a/test/prism/errors/void_value_expression_in_modifier.txt b/test/prism/errors/void_value_expression_in_modifier.txt
new file mode 100644
index 0000000000..7d7b444e33
--- /dev/null
+++ b/test/prism/errors/void_value_expression_in_modifier.txt
@@ -0,0 +1,13 @@
+1 if (return)
+ ^~~~~~ unexpected void value expression
+1 unless (return)
+ ^~~~~~ unexpected void value expression
+1 while (return)
+ ^~~~~~ unexpected void value expression
+1 until (return)
+ ^~~~~~ unexpected void value expression
+(return) => a
+ ^~~~~~ unexpected void value expression
+(return) in a
+ ^~~~~~ unexpected void value expression
+
diff --git a/test/prism/errors/void_value_expression_in_statement.txt b/test/prism/errors/void_value_expression_in_statement.txt
new file mode 100644
index 0000000000..87dbfa5cc9
--- /dev/null
+++ b/test/prism/errors/void_value_expression_in_statement.txt
@@ -0,0 +1,26 @@
+if (return)
+ ^~~~~~ unexpected void value expression
+end
+unless (return)
+ ^~~~~~ unexpected void value expression
+end
+while (return)
+ ^~~~~~ unexpected void value expression
+end
+until (return)
+ ^~~~~~ unexpected void value expression
+end
+case (return)
+ ^~~~~~ unexpected void value expression
+when 1
+end
+class A < (return)
+ ^~~~~~ unexpected void value expression
+end
+class << (return)
+ ^~~~~~ unexpected void value expression
+end
+for x in (return)
+ ^~~~~~ unexpected void value expression
+end
+
diff --git a/test/prism/errors/void_value_expression_in_unary_call.txt b/test/prism/errors/void_value_expression_in_unary_call.txt
new file mode 100644
index 0000000000..61e849255c
--- /dev/null
+++ b/test/prism/errors/void_value_expression_in_unary_call.txt
@@ -0,0 +1,5 @@
++(return)
+ ^~~~~~ unexpected void value expression
+not return
+ ^~~~~~ unexpected void value expression
+
diff --git a/test/prism/errors/while_endless_method.txt b/test/prism/errors/while_endless_method.txt
new file mode 100644
index 0000000000..cdd7ba9aba
--- /dev/null
+++ b/test/prism/errors/while_endless_method.txt
@@ -0,0 +1,5 @@
+while def f = g do end
+ ^ expected a predicate expression for the `while` statement
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~~~~ expected an `end` to close the `while` statement
+
diff --git a/test/prism/errors/writing_numbered_parameter.txt b/test/prism/errors/writing_numbered_parameter.txt
new file mode 100644
index 0000000000..17dcc6e8f0
--- /dev/null
+++ b/test/prism/errors/writing_numbered_parameter.txt
@@ -0,0 +1,3 @@
+-> { _1 = 0 }
+ ^~ _1 is reserved for numbered parameters
+
diff --git a/test/prism/errors/xstring_concat.txt b/test/prism/errors/xstring_concat.txt
new file mode 100644
index 0000000000..f4d453d68d
--- /dev/null
+++ b/test/prism/errors/xstring_concat.txt
@@ -0,0 +1,5 @@
+<<`EOC` "bar"
+^~~~~~~ expected a string for concatenation
+echo foo
+EOC
+
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
new file mode 100644
index 0000000000..9dd7fbe3fe
--- /dev/null
+++ b/test/prism/errors_test.rb
@@ -0,0 +1,135 @@
+# 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[ENV.fetch("FOCUS", "**/*.txt"), base: base]
+
+ PARSE_Y_EXCLUDES = [
+ # https://bugs.ruby-lang.org/issues/20409
+ "#{base}/4.1/end_block_exit.txt"
+ ]
+
+ filepaths.each do |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
+
+ def test_newline_preceding_eof
+ err = Prism.parse("foo(").errors.first
+ assert_equal 1, err.location.start_line
+
+ err = Prism.parse("foo(\n").errors.first
+ assert_equal 1, err.location.start_line
+
+ err = Prism.parse("foo(\n\n\n\n\n").errors.first
+ assert_equal 5, err.location.start_line
+ end
+
+ def test_embdoc_ending
+ source = <<~RUBY
+ =begin\n=end
+ =begin\n=end\0
+ =begin\n=end\C-d
+ =begin\n=end\C-z
+ RUBY
+
+ source.each_line do |line|
+ assert_valid_syntax(source)
+ assert_predicate Prism.parse(source), :success?
+ end
+ end
+
+ def test_unterminated_string_closing
+ statement = Prism.parse_statement("'hello")
+ assert_equal statement.unescaped, "hello"
+ assert_nil statement.closing
+ end
+
+ def test_unterminated_interpolated_string_closing
+ statement = Prism.parse_statement('"hello')
+ assert_equal statement.unescaped, "hello"
+ assert_nil statement.closing
+ end
+
+ def test_unterminated_empty_string_closing
+ statement = Prism.parse_statement('"')
+ assert_empty statement.unescaped
+ assert_nil statement.closing
+ end
+
+ def test_regexp_encoding_option_mismatch_error
+ # UTF-8 char with ASCII-8BIT modifier
+ result = Prism.parse('/Ȃ/n')
+ assert_includes result.errors.map(&:type), :regexp_encoding_option_mismatch
+
+ # UTF-8 char with EUC-JP modifier
+ result = Prism.parse('/Ȃ/e')
+ assert_includes result.errors.map(&:type), :regexp_encoding_option_mismatch
+
+ # UTF-8 char with Windows-31J modifier
+ result = Prism.parse('/Ȃ/s')
+ assert_includes result.errors.map(&:type), :regexp_encoding_option_mismatch
+
+ # UTF-8 char with UTF-8 modifier
+ result = Prism.parse('/Ȃ/u')
+ assert_empty result.errors
+ end
+
+ def test_incomplete_def_closing_loc
+ statement = Prism.parse_statement("def f; 123")
+ assert_nil(statement.end_keyword)
+ end
+
+ def test_unclosed_interpolation
+ statement = Prism.parse_statement("\"\#{")
+ assert_equal('"', statement.opening)
+ assert_nil(statement.closing)
+
+ assert_equal(1, statement.parts.count)
+ assert_equal('#{', statement.parts[0].opening)
+ assert_equal("", statement.parts[0].closing)
+ assert_nil(statement.parts[0].statements)
+ end
+
+ def test_unclosed_heredoc_and_interpolation
+ statement = Prism.parse_statement("<<D\n\#{")
+ assert_equal("<<D", statement.opening)
+ assert_nil(statement.closing)
+
+ assert_equal(1, statement.parts.count)
+ assert_equal('#{', statement.parts[0].opening)
+ assert_equal("", statement.parts[0].closing)
+ assert_nil(statement.parts[0].statements)
+ end
+
+ private
+
+ 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/, "")
+ if CURRENT_MAJOR_MINOR == version && !PARSE_Y_EXCLUDES.include?(filepath)
+ refute_valid_syntax(source)
+ end
+
+ result = Prism.parse(source, version: version)
+ errors = result.errors
+ refute_empty errors, "Expected errors in #{filepath}"
+
+ actual = result.errors_format
+ if expected != actual && ENV["UPDATE_SNAPSHOTS"]
+ File.write(filepath, actual)
+ end
+
+ assert_equal expected, actual, "Expected errors to match for #{filepath}"
+ end
+ end
+end
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/3.3-3.3/it.txt b/test/prism/fixtures/3.3-3.3/it.txt
new file mode 100644
index 0000000000..5410b01e71
--- /dev/null
+++ b/test/prism/fixtures/3.3-3.3/it.txt
@@ -0,0 +1,5 @@
+x do
+ it
+end
+
+-> { it }
diff --git a/test/prism/fixtures/3.3-3.3/it_indirect_writes.txt b/test/prism/fixtures/3.3-3.3/it_indirect_writes.txt
new file mode 100644
index 0000000000..bb87e9483e
--- /dev/null
+++ b/test/prism/fixtures/3.3-3.3/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.3-3.3/it_read_and_assignment.txt b/test/prism/fixtures/3.3-3.3/it_read_and_assignment.txt
new file mode 100644
index 0000000000..2cceeb2a54
--- /dev/null
+++ b/test/prism/fixtures/3.3-3.3/it_read_and_assignment.txt
@@ -0,0 +1 @@
+42.tap { p it; it = it; p it }
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.3-4.0/end_block_exit.txt b/test/prism/fixtures/3.3-4.0/end_block_exit.txt
new file mode 100644
index 0000000000..8ebf0d6369
--- /dev/null
+++ b/test/prism/fixtures/3.3-4.0/end_block_exit.txt
@@ -0,0 +1,11 @@
+END {
+ return
+}
+
+END {
+ break
+}
+
+END {
+ next
+}
diff --git a/test/prism/fixtures/3.3-4.0/void_value.txt b/test/prism/fixtures/3.3-4.0/void_value.txt
new file mode 100644
index 0000000000..bfb8eff09c
--- /dev/null
+++ b/test/prism/fixtures/3.3-4.0/void_value.txt
@@ -0,0 +1,29 @@
+x = begin
+ foo
+rescue
+ return
+else
+ return
+end
+
+x = case
+ when 1 then return
+ else return
+end
+
+x = case 1
+ in 2 then return
+ else return
+end
+
+x = begin
+ return
+ "NG"
+end
+
+x = if rand < 0.5
+ return
+ "NG"
+else
+ 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/4.0/endless_methods_command_call.txt b/test/prism/fixtures/4.0/endless_methods_command_call.txt
new file mode 100644
index 0000000000..146a6ee579
--- /dev/null
+++ b/test/prism/fixtures/4.0/endless_methods_command_call.txt
@@ -0,0 +1,11 @@
+private def foo = puts "Hello"
+private def foo = puts "Hello", "World"
+private def foo = puts "Hello" do expr end
+private def foo() = puts "Hello"
+private def foo(x) = puts x
+private def obj.foo = puts "Hello"
+private def obj.foo() = puts "Hello"
+private def obj.foo(x) = puts x
+
+private def foo = bar baz
+private def foo = bar baz do expr end
diff --git a/test/prism/fixtures/4.0/leading_logical.txt b/test/prism/fixtures/4.0/leading_logical.txt
new file mode 100644
index 0000000000..ee87e00d4f
--- /dev/null
+++ b/test/prism/fixtures/4.0/leading_logical.txt
@@ -0,0 +1,16 @@
+1
+&& 2
+&& 3
+
+1
+|| 2
+|| 3
+
+1
+and 2
+and 3
+
+1
+or 2
+or 3
+
diff --git a/test/prism/fixtures/4.1/noblock.txt b/test/prism/fixtures/4.1/noblock.txt
new file mode 100644
index 0000000000..2395393e22
--- /dev/null
+++ b/test/prism/fixtures/4.1/noblock.txt
@@ -0,0 +1,4 @@
+def foo(&nil)
+end
+
+-> (&nil) {}
diff --git a/test/prism/fixtures/4.1/trailing_comma_after_method_arguments.txt b/test/prism/fixtures/4.1/trailing_comma_after_method_arguments.txt
new file mode 100644
index 0000000000..ef1385d973
--- /dev/null
+++ b/test/prism/fixtures/4.1/trailing_comma_after_method_arguments.txt
@@ -0,0 +1,15 @@
+def foo(a,b,c,);end
+
+def foo(a,b,*c,);end
+
+def foo(a,b,*,);end
+
+def foo(a,b,**c,);end
+
+def foo(a,b,**,);end
+
+def foo(
+ a,
+ b,
+ c,
+);end
diff --git a/test/prism/fixtures/4.1/void_value.txt b/test/prism/fixtures/4.1/void_value.txt
new file mode 100644
index 0000000000..915112d623
--- /dev/null
+++ b/test/prism/fixtures/4.1/void_value.txt
@@ -0,0 +1,7 @@
+x = begin
+ return
+rescue
+ "OK"
+else
+ return
+end
diff --git a/test/prism/fixtures/__END__.txt b/test/prism/fixtures/__END__.txt
new file mode 100644
index 0000000000..c0f4f28004
--- /dev/null
+++ b/test/prism/fixtures/__END__.txt
@@ -0,0 +1,3 @@
+foo
+__END__
+Available in DATA constant
diff --git a/test/prism/fixtures/alias.txt b/test/prism/fixtures/alias.txt
new file mode 100644
index 0000000000..376dacd7cc
--- /dev/null
+++ b/test/prism/fixtures/alias.txt
@@ -0,0 +1,23 @@
+alias :foo :bar
+
+alias %s[abc] %s[def]
+
+alias :'abc' :'def'
+
+alias :"abc#{1}" :'def'
+
+alias $a $'
+
+alias foo bar
+
+alias $foo $bar
+
+alias foo if
+
+alias foo <=>
+
+alias :== :eql?
+
+alias A B
+
+alias :A :B
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/arithmetic.txt b/test/prism/fixtures/arithmetic.txt
new file mode 100644
index 0000000000..b1e1267b95
--- /dev/null
+++ b/test/prism/fixtures/arithmetic.txt
@@ -0,0 +1,13 @@
+foo !bar
+
+-foo*bar
+
++foo**bar
+
+foo ~bar
+
+foo << bar << baz
+
+-1**2
+
+-1.zero?
diff --git a/test/prism/fixtures/arrays.txt b/test/prism/fixtures/arrays.txt
new file mode 100644
index 0000000000..2897189518
--- /dev/null
+++ b/test/prism/fixtures/arrays.txt
@@ -0,0 +1,122 @@
+[*a]
+
+foo[bar, baz] = 1, 2, 3
+
+[a: [:b, :c]]
+
+
+
+[:a, :b,
+:c,1,
+
+
+
+:d,
+]
+
+
+[:a, :b,
+:c,1,
+
+
+
+:d
+
+
+]
+
+[foo => bar]
+
+foo[bar][baz] = qux
+
+foo[bar][baz]
+
+[
+]
+
+foo[bar, baz]
+
+foo[bar, baz] = qux
+
+foo[0], bar[0] = 1, 2
+
+foo[bar[baz] = qux]
+
+foo[bar]
+
+foo[bar] = baz
+
+[**{}]
+
+[**kw]
+
+[1, **kw]
+
+[1, **kw, **{}, **kw]
+
+[
+ foo => bar,
+]
+
+
+%i#one two three#
+
+%w#one two three#
+
+%x#one two three#
+
+
+%i@one two three@
+
+%w@one two three@
+
+%x@one two three@
+
+
+%i{one two three}
+
+%w{one two three}
+
+%x{one two three}
+
+%w[\C:]
+
+foo[] += 1
+
+foo[] ||= 1
+
+foo[] &&= 1
+
+foo.foo[] += 1
+
+foo.foo[] ||= 1
+
+foo.foo[] &&= 1
+
+foo[bar] += 1
+
+foo[bar] ||= 1
+
+foo[bar] &&= 1
+
+foo.foo[bar] += 1
+
+foo.foo[bar] ||= 1
+
+foo.foo[bar] &&= 1
+
+def f(*); a[*]; end
+
+def f(*); a[1, *]; end
+
+def f(*); a[*] = 1; end
+
+def f(*); a[1, *] = 1; end
+
+def f(*); a[*] += 1; end
+
+def f(*); a[1, *] &&= 1; end
+
+def f(*); rescue => a[*]; end
+
+def f(*); rescue => a[1, *]; end
diff --git a/test/prism/fixtures/begin_ensure.txt b/test/prism/fixtures/begin_ensure.txt
new file mode 100644
index 0000000000..6cfb627453
--- /dev/null
+++ b/test/prism/fixtures/begin_ensure.txt
@@ -0,0 +1,21 @@
+begin
+a
+ensure
+b
+end
+
+begin; a; ensure; b; end
+
+begin a
+ ensure b
+ end
+
+begin a; ensure b; end
+
+begin begin:s.l begin ensure Module.new do
+ begin
+ break
+ ensure Module.new do
+ end
+ end
+end end end end
diff --git a/test/prism/fixtures/begin_rescue.txt b/test/prism/fixtures/begin_rescue.txt
new file mode 100644
index 0000000000..790574f4ff
--- /dev/null
+++ b/test/prism/fixtures/begin_rescue.txt
@@ -0,0 +1,85 @@
+begin; a; rescue; b; else; c; end
+
+begin; a; rescue; b; else; c; ensure; d; end
+
+begin; rescue ; end
+
+begin; rescue ; ensure ; end
+
+begin; rescue ; else ; end
+
+begin
+a
+end
+
+begin; a; end
+
+begin a
+ end
+
+begin a; end
+
+begin
+a
+rescue
+b
+rescue
+c
+rescue
+d
+end
+
+begin
+ a
+rescue Exception => ex
+ b
+rescue AnotherException, OneMoreException => ex
+ c
+end
+
+begin
+ a
+rescue Exception => ex
+ b
+ensure
+ b
+end
+
+%!abc!
+
+begin
+a
+rescue
+b
+end
+
+begin;a;rescue;b;end
+
+begin
+a;rescue
+b;end
+
+begin
+a
+rescue Exception
+b
+end
+
+begin
+a
+rescue Exception, CustomException
+b
+end
+
+begin
+ a
+rescue Exception, CustomException => ex
+ b
+end
+
+begin
+ a
+rescue Exception => ex
+ b
+end
+
diff --git a/test/prism/fixtures/blocks.txt b/test/prism/fixtures/blocks.txt
new file mode 100644
index 0000000000..51ec84950c
--- /dev/null
+++ b/test/prism/fixtures/blocks.txt
@@ -0,0 +1,62 @@
+foo[bar] { baz }
+
+foo[bar] do
+baz
+end
+
+x.reduce(0) { |x, memo| memo += x }
+
+foo do end
+
+foo bar, (baz do end)
+
+foo bar do end
+
+foo bar baz do end
+
+foo do |a = b[1]|
+end
+
+foo do
+rescue
+end
+
+foo do
+ bar do
+ baz do
+ end
+ end
+end
+
+foo[bar] { baz }
+
+foo { |x, y = 2, z:| x }
+
+foo { |x| }
+
+fork = 1
+fork do |a|
+end
+
+fork { |a| }
+
+C do
+end
+
+C {}
+
+foo lambda { |
+ a: 1,
+ b: 2
+ |
+}
+
+foo do |bar,| end
+
+foo bar baz, qux do end
+
+foo.bar baz do end
+
+foo.bar baz do end.qux quux do end
+
+foo bar, baz do |x| x end
diff --git a/test/prism/fixtures/bom_leading_space.txt b/test/prism/fixtures/bom_leading_space.txt
new file mode 100644
index 0000000000..48d3ee50ea
--- /dev/null
+++ b/test/prism/fixtures/bom_leading_space.txt
@@ -0,0 +1 @@
+ p (42)
diff --git a/test/prism/fixtures/bom_spaces.txt b/test/prism/fixtures/bom_spaces.txt
new file mode 100644
index 0000000000..c18ad4c21a
--- /dev/null
+++ b/test/prism/fixtures/bom_spaces.txt
@@ -0,0 +1 @@
+p ( 42 )
diff --git a/test/prism/fixtures/boolean_operators.txt b/test/prism/fixtures/boolean_operators.txt
new file mode 100644
index 0000000000..dd0b9c9f01
--- /dev/null
+++ b/test/prism/fixtures/boolean_operators.txt
@@ -0,0 +1,5 @@
+a &&= b
+
+a += b
+
+a ||= b
diff --git a/test/prism/fixtures/booleans.txt b/test/prism/fixtures/booleans.txt
new file mode 100644
index 0000000000..d9417254b6
--- /dev/null
+++ b/test/prism/fixtures/booleans.txt
@@ -0,0 +1,3 @@
+false
+
+true
diff --git a/test/prism/fixtures/break.txt b/test/prism/fixtures/break.txt
new file mode 100644
index 0000000000..d823f866df
--- /dev/null
+++ b/test/prism/fixtures/break.txt
@@ -0,0 +1,33 @@
+tap { break }
+
+tap { break (1), (2), (3) }
+
+tap { break 1 }
+
+tap { break 1, 2,
+3 }
+
+tap { break 1, 2, 3 }
+
+tap { break [1, 2, 3] }
+
+tap { break(
+ 1
+ 2
+) }
+
+tap { break() }
+
+tap { break(1) }
+
+tap { (break 1) }
+
+tap { foo && (break 1) }
+
+foo { break 42 } == 42
+
+foo { |a| break } == 42
+
+while _ && break; end
+
+until _ && break; end
diff --git a/test/prism/fixtures/case.txt b/test/prism/fixtures/case.txt
new file mode 100644
index 0000000000..733e1e54d2
--- /dev/null
+++ b/test/prism/fixtures/case.txt
@@ -0,0 +1,55 @@
+case :hi
+when :hi
+end
+
+case true; when true; puts :hi; when false; puts :bye; end
+
+case; when *foo; end
+
+case :hi
+when :hi
+else
+:b
+end
+
+case this; when FooBar, BazBonk; end
+
+case
+when foo == bar
+end
+
+case
+when a
+else
+ # empty
+end
+
+case type;
+ ;when :b;
+ ; else;
+ end
+
+case ;;;;;;;; when 1; end
+
+case 1 in 2
+when 3
+end
+
+case 1 in 2; when 3; end
+
+case 1 in 2
+in 3
+end
+
+case 1 in 2; in 3; end
+
+case a
+in b if c and d
+ e
+end
+
+1.then do
+ case 1
+ in ^_1
+ end
+end
diff --git a/test/prism/fixtures/case_in_hash_key.txt b/test/prism/fixtures/case_in_hash_key.txt
new file mode 100644
index 0000000000..75ac8a846f
--- /dev/null
+++ b/test/prism/fixtures/case_in_hash_key.txt
@@ -0,0 +1,6 @@
+case 1
+in 2
+ A.print message:
+in 3
+ A.print message:
+end
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/fixtures/character_literal.txt b/test/prism/fixtures/character_literal.txt
new file mode 100644
index 0000000000..920332123f
--- /dev/null
+++ b/test/prism/fixtures/character_literal.txt
@@ -0,0 +1,2 @@
+# encoding: Windows-31J
+p ?\u3042""
diff --git a/test/prism/fixtures/classes.txt b/test/prism/fixtures/classes.txt
new file mode 100644
index 0000000000..056cb00e82
--- /dev/null
+++ b/test/prism/fixtures/classes.txt
@@ -0,0 +1,35 @@
+class A a = 1 end
+
+class A; ensure; end
+
+class A; rescue; else; ensure; end
+
+class A < B
+a = 1
+end
+
+class << not foo
+end
+
+class A; class << self; ensure; end; end
+
+class A; class << self; rescue; else; ensure; end; end
+
+class << foo.bar
+end
+
+class << foo.bar;end
+
+class << self
+end
+
+class << self;end
+
+class << self
+1 + 2
+end
+
+class << self;1 + 2;end
+
+class A < B[1]
+end
diff --git a/test/prism/fixtures/command_method_call.txt b/test/prism/fixtures/command_method_call.txt
new file mode 100644
index 0000000000..182b87948b
--- /dev/null
+++ b/test/prism/fixtures/command_method_call.txt
@@ -0,0 +1,41 @@
+foo 1
+
+foo bar 1
+
+foo 1 if bar 2
+
+foo 1 unless bar 2
+
+foo 1 while bar 2
+
+foo 1 until bar 2
+
+foo 1 rescue bar 2
+
+foo[bar 1]
+
+foo 1 and bar 2
+
+foo 1 or bar 2
+
+not foo 1
+
+foo = bar = baz 1
+
+def foo = bar 1
+
+1.foo 2
+
+1.foo.bar 2
+
+1.foo[2].bar 3
+
+1.foo(2).bar 3
+
+1.foo(&2).bar 3
+
+!foo 1 and !bar 2
+
+!foo 1 or !bar 2
+
+not !foo 1
diff --git a/test/prism/fixtures/command_method_call_2.txt b/test/prism/fixtures/command_method_call_2.txt
new file mode 100644
index 0000000000..8bd40cff9e
--- /dev/null
+++ b/test/prism/fixtures/command_method_call_2.txt
@@ -0,0 +1 @@
+foo(bar baz, bat)
diff --git a/test/prism/fixtures/command_method_call_3.txt b/test/prism/fixtures/command_method_call_3.txt
new file mode 100644
index 0000000000..6de0446aa9
--- /dev/null
+++ b/test/prism/fixtures/command_method_call_3.txt
@@ -0,0 +1,19 @@
+foo(bar 1, key => '2')
+
+foo(bar 1, KEY => '2')
+
+foo(bar 1, :key => '2')
+
+foo(bar 1, { baz: :bat } => '2')
+
+foo bar - %i[baz] => '2'
+
+foo(bar {} => '2')
+
+foo(bar baz {} => '2')
+
+foo(bar do end => '2')
+
+foo(1, bar {} => '2')
+
+foo(1, bar do end => '2')
diff --git a/test/prism/fixtures/comment_single.txt b/test/prism/fixtures/comment_single.txt
new file mode 100644
index 0000000000..72037a6ea1
--- /dev/null
+++ b/test/prism/fixtures/comment_single.txt
@@ -0,0 +1 @@
+foo # Bar \ No newline at end of file
diff --git a/test/prism/fixtures/comments.txt b/test/prism/fixtures/comments.txt
new file mode 100644
index 0000000000..9bd853e927
--- /dev/null
+++ b/test/prism/fixtures/comments.txt
@@ -0,0 +1,24 @@
+a
+ # Comment
+b
+
+c # Comment
+d
+
+e
+# Comment
+ .f
+
+g
+ # Comment
+.h
+
+i # Comment
+.j
+
+k # Comment
+ .l
+
+m
+ # Comment
+ &.n
diff --git a/test/prism/fixtures/constants.txt b/test/prism/fixtures/constants.txt
new file mode 100644
index 0000000000..d86f8d3402
--- /dev/null
+++ b/test/prism/fixtures/constants.txt
@@ -0,0 +1,184 @@
+A::B
+
+A::B::C
+
+a::B
+
+A::B = 1
+
+A = 1
+
+ABC
+
+Foo 1
+
+Foo *bar
+
+Foo **bar
+
+Foo &bar
+
+Foo::Bar *baz
+
+Foo::Bar **baz
+
+Foo::Bar &baz
+
+::A::foo
+
+::A = 1
+
+::A::B = 1
+
+::A::B
+
+::A
+
+A::false
+
+A::B::true
+
+A::&
+
+A::`
+
+A::!
+
+A::!=
+
+A::^
+
+A::==
+
+A::===
+
+A::=~
+
+A::>
+
+A::>=
+
+A::>>
+
+A::<<
+
+A::\
+#
+C
+
+A::alias
+
+A::and
+
+A::begin
+
+A::BEGIN
+
+A::break
+
+A::class
+
+A::def
+
+A::defined
+
+A::do
+
+A::else
+
+A::elsif
+
+A::end
+
+A::END
+
+A::ensure
+
+A::false
+
+A::for
+
+A::if
+
+A::in
+
+A::next
+
+A::nil
+
+A::not
+
+A::or
+
+A::redo
+
+A::rescue
+
+A::retry
+
+A::return
+
+A::self
+
+A::super
+
+A::then
+
+A::true
+
+A::undef
+
+A::unless
+
+A::until
+
+A::when
+
+A::while
+
+A::yield
+
+A::__ENCODING__
+
+A::__FILE__
+
+A::__LINE__
+
+A::<
+
+A::<=>
+
+A::<<
+
+A::-
+
+A::%
+
+A::%i
+
+A::%w
+
+A::%x
+
+A::%I
+
+A::%W
+
+A::|
+
+A::+
+
+A::/
+
+A::*
+
+A::**
+
+A::~
+
+A::_::
+C
+
+A::_..
+
+A::__END__
diff --git a/test/prism/fixtures/dash_heredocs.txt b/test/prism/fixtures/dash_heredocs.txt
new file mode 100644
index 0000000000..3e663fae63
--- /dev/null
+++ b/test/prism/fixtures/dash_heredocs.txt
@@ -0,0 +1,63 @@
+<<-EOF
+ a
+EOF
+
+<<-FIRST + <<-SECOND
+ a
+FIRST
+ b
+SECOND
+
+<<-`EOF`
+ a
+#{b}
+EOF
+
+<<-EOF #comment
+ a
+EOF
+
+<<-EOF
+ a
+ b
+ EOF
+
+<<-"EOF"
+ a
+#{b}
+EOF
+
+<<-EOF
+ a
+#{b}
+EOF
+
+%#abc#
+
+<<-EOF
+ a
+ b
+EOF
+
+<<-''
+
+
+<<-'EOF'
+ a #{1}
+EOF
+
+<<-A + <<-B
+ a
+A
+ b
+ #{2
+ }
+B
+
+<<-A + <<-B
+ a
+A
+ b
+ #{
+ 2}
+B
diff --git a/test/prism/fixtures/defined.txt b/test/prism/fixtures/defined.txt
new file mode 100644
index 0000000000..09fc0a29e7
--- /dev/null
+++ b/test/prism/fixtures/defined.txt
@@ -0,0 +1,19 @@
+defined? 1 and defined? 2
+
+defined?(x %= 2)
+
+defined?(foo and bar)
+
+defined? 1
+
+defined?("foo"
+)
+
+defined?
+1
+
+defined?
+(1)
+
+defined?
+()
diff --git a/test/prism/fixtures/dos_endings.txt b/test/prism/fixtures/dos_endings.txt
new file mode 100644
index 0000000000..c105522fa1
--- /dev/null
+++ b/test/prism/fixtures/dos_endings.txt
@@ -0,0 +1,20 @@
+puts "hi"\
+ "there"
+
+%I{a\
+b}
+
+<<-E
+ 1 \
+ 2
+ 3
+E
+
+x = %
+
+
+
+a = foo(<<~EOF.chop)
+
+ baz
+ EOF
diff --git a/test/prism/fixtures/dstring.txt b/test/prism/fixtures/dstring.txt
new file mode 100644
index 0000000000..ef698d8fe9
--- /dev/null
+++ b/test/prism/fixtures/dstring.txt
@@ -0,0 +1,42 @@
+"foo
+ bar"
+
+"foo
+ #{bar}"
+
+"fo
+o" "ba
+r"
+
+"
+foo\
+"
+
+"
+foo\\
+"
+
+"
+foo\\\
+"
+
+"
+foo\\\\
+"
+
+"
+foo\\\\\
+"
+
+"
+foo\
+b\nar
+#{}
+"
+
+"foo
+\n#{}bar\n\n#{}
+a\nb\n#{}\nc\n"
+
+"
+’"
diff --git a/test/prism/fixtures/dsym_str.txt b/test/prism/fixtures/dsym_str.txt
new file mode 100644
index 0000000000..0af0a8ddaf
--- /dev/null
+++ b/test/prism/fixtures/dsym_str.txt
@@ -0,0 +1,5 @@
+:"foo
+ bar"
+
+:"
+’"
diff --git a/test/prism/fixtures/embdoc_no_newline_at_end.txt b/test/prism/fixtures/embdoc_no_newline_at_end.txt
new file mode 100644
index 0000000000..7dc2e32d73
--- /dev/null
+++ b/test/prism/fixtures/embdoc_no_newline_at_end.txt
@@ -0,0 +1,2 @@
+=begin
+=end \ No newline at end of file
diff --git a/test/prism/fixtures/emoji_method_calls.txt b/test/prism/fixtures/emoji_method_calls.txt
new file mode 100644
index 0000000000..96d0daba33
--- /dev/null
+++ b/test/prism/fixtures/emoji_method_calls.txt
@@ -0,0 +1 @@
+foo.🌊 = 1
diff --git a/test/prism/fixtures/encoding_binary.txt b/test/prism/fixtures/encoding_binary.txt
new file mode 100644
index 0000000000..f3dfc85abd
--- /dev/null
+++ b/test/prism/fixtures/encoding_binary.txt
@@ -0,0 +1,9 @@
+# encoding: binary
+
+"\xcd"
+
+:"\xcd"
+
+/#{"\xcd"}/
+
+%W[\xC0]
diff --git a/test/prism/fixtures/encoding_euc_jp.txt b/test/prism/fixtures/encoding_euc_jp.txt
new file mode 100644
index 0000000000..bbee76eae5
--- /dev/null
+++ b/test/prism/fixtures/encoding_euc_jp.txt
@@ -0,0 +1,6 @@
+# encoding: euc-jp
+
+# \x8E indicates a double-byte character, \x01 is not a valid second byte in euc-jp
+"\x8E\x01"
+
+%W["\x8E\x01"]
diff --git a/test/prism/fixtures/endless_method_as_default_arg.txt b/test/prism/fixtures/endless_method_as_default_arg.txt
new file mode 100644
index 0000000000..0063d9a8fa
--- /dev/null
+++ b/test/prism/fixtures/endless_method_as_default_arg.txt
@@ -0,0 +1,11 @@
+def foo(a = def f = 1); end
+
+def foo(a = def f = 1, b); end
+
+def foo(b, a = def f = 1); end
+
+def foo(a: def f = 1); end
+
+def foo(a = def f = 1+2); end
+
+->(a = def f = 1) {}
diff --git a/test/prism/fixtures/endless_methods.txt b/test/prism/fixtures/endless_methods.txt
new file mode 100644
index 0000000000..6e0488a5ee
--- /dev/null
+++ b/test/prism/fixtures/endless_methods.txt
@@ -0,0 +1,11 @@
+def foo = 1
+
+def bar = A ""
+
+def method = 1 + 2 + 3
+
+x = def f = p 1
+
+def foo = bar baz
+
+def foo = bar(baz)
diff --git a/test/prism/fixtures/endless_range_in_conditional.txt b/test/prism/fixtures/endless_range_in_conditional.txt
new file mode 100644
index 0000000000..6048008584
--- /dev/null
+++ b/test/prism/fixtures/endless_range_in_conditional.txt
@@ -0,0 +1,3 @@
+if 1..2 ; end
+if ..1 ; end
+if 1.. ; end
diff --git a/test/prism/fixtures/escaped_newline_with_trailing_content.txt b/test/prism/fixtures/escaped_newline_with_trailing_content.txt
new file mode 100644
index 0000000000..fe947a3f10
--- /dev/null
+++ b/test/prism/fixtures/escaped_newline_with_trailing_content.txt
@@ -0,0 +1,2 @@
+"A
+B\nCC"
diff --git a/test/prism/fixtures/for.txt b/test/prism/fixtures/for.txt
new file mode 100644
index 0000000000..b6eb2cb24f
--- /dev/null
+++ b/test/prism/fixtures/for.txt
@@ -0,0 +1,19 @@
+for i in 1..10
+i
+end
+
+for i in 1..10; i; end
+
+for i,j in 1..10
+i
+end
+
+for i,j,k in 1..10
+i
+end
+
+for i in 1..10 do
+i
+end
+
+for i in 1..10; i; end
diff --git a/test/prism/fixtures/global_variables.txt b/test/prism/fixtures/global_variables.txt
new file mode 100644
index 0000000000..3dc52722a0
--- /dev/null
+++ b/test/prism/fixtures/global_variables.txt
@@ -0,0 +1,93 @@
+$global_variable
+
+$_
+
+$-w
+
+$LOAD_PATH
+
+$stdin
+
+$stdout
+
+$stderr
+
+$!
+
+$?
+
+$~
+
+$&
+
+$`
+
+$'
+
+$+
+
+$:
+
+$;
+
+$,
+
+$DEBUG
+
+$FILENAME
+
+$0
+
+$-0
+
+$LOADED_FEATURES
+
+$VERBOSE
+
+$-K
+
+:$global_variable
+
+:$_
+
+:$-w
+
+:$LOAD_PATH
+
+:$stdin
+
+:$stdout
+
+:$stderr
+
+:$!
+
+:$?
+
+:$~
+
+:$&
+
+:$`
+
+:$'
+
+:$+
+
+:$:
+
+:$;
+
+:$DEBUG
+
+:$FILENAME
+
+:$0
+
+:$-0
+
+:$LOADED_FEATURES
+
+:$VERBOSE
+
+:$-K
diff --git a/test/prism/fixtures/hashes.txt b/test/prism/fixtures/hashes.txt
new file mode 100644
index 0000000000..0afb8db496
--- /dev/null
+++ b/test/prism/fixtures/hashes.txt
@@ -0,0 +1,28 @@
+{}
+
+{
+}
+
+{ a => b, c => d }
+
+{ a => b, **c }
+
+{
+ a: b,
+ c: d
+
+
+
+ }
+
+{ a: b, c: d, **e, f: g }
+
+{ "a": !b? }
+
+a = 1
+tap do
+ b = 1
+ { a:, b:, c:, D: }
+end
+
+{ a: -1 }
diff --git a/test/prism/fixtures/heredoc.txt b/test/prism/fixtures/heredoc.txt
new file mode 100644
index 0000000000..f94fd912df
--- /dev/null
+++ b/test/prism/fixtures/heredoc.txt
@@ -0,0 +1,2 @@
+<<TEXT
+TEXT
diff --git a/test/prism/fixtures/heredoc_dedent_line_continuation.txt b/test/prism/fixtures/heredoc_dedent_line_continuation.txt
new file mode 100644
index 0000000000..661db490c7
--- /dev/null
+++ b/test/prism/fixtures/heredoc_dedent_line_continuation.txt
@@ -0,0 +1,5 @@
+<<~FOO
+ foo\
+ \
+ bar
+FOO
diff --git a/test/prism/fixtures/heredoc_percent_q_newline_delimiter.txt b/test/prism/fixtures/heredoc_percent_q_newline_delimiter.txt
new file mode 100644
index 0000000000..dbfa0bf4b4
--- /dev/null
+++ b/test/prism/fixtures/heredoc_percent_q_newline_delimiter.txt
@@ -0,0 +1,22 @@
+%Q
+#{<<B}
+B
+
+%
+#{<<B}
+B
+
+<<A; %Q
+A
+#{<<B}
+B
+
+<<A; %
+A
+#{<<B}
+B
+
+# \r\n
+%Q
+#{<<B}
+B
diff --git a/test/prism/fixtures/heredoc_with_carriage_returns.txt b/test/prism/fixtures/heredoc_with_carriage_returns.txt
new file mode 100644
index 0000000000..32a2d87b24
--- /dev/null
+++ b/test/prism/fixtures/heredoc_with_carriage_returns.txt
@@ -0,0 +1,2 @@
+<<TEXT
+TEXT
diff --git a/test/prism/fixtures/heredoc_with_comment.txt b/test/prism/fixtures/heredoc_with_comment.txt
new file mode 100644
index 0000000000..8e7b7275bd
--- /dev/null
+++ b/test/prism/fixtures/heredoc_with_comment.txt
@@ -0,0 +1,3 @@
+<<-TARGET.chomp # the heredoc end token doesn't always precede the comment
+ content makes for an obvious error
+TARGET \ No newline at end of file
diff --git a/test/prism/fixtures/heredoc_with_escaped_newline_at_start.txt b/test/prism/fixtures/heredoc_with_escaped_newline_at_start.txt
new file mode 100644
index 0000000000..81f314e0b3
--- /dev/null
+++ b/test/prism/fixtures/heredoc_with_escaped_newline_at_start.txt
@@ -0,0 +1,7 @@
+<<-TARGET.gsub /^\s{/, ''\
+TARGET
+
+
+<<-TARGET.gsub /^\s{/, ''\
+TARGET
+
diff --git a/test/prism/fixtures/heredoc_with_trailing_newline.txt b/test/prism/fixtures/heredoc_with_trailing_newline.txt
new file mode 100644
index 0000000000..13771bf3ac
--- /dev/null
+++ b/test/prism/fixtures/heredoc_with_trailing_newline.txt
@@ -0,0 +1,2 @@
+<<-END
+END \ No newline at end of file
diff --git a/test/prism/fixtures/heredocs_leading_whitespace.txt b/test/prism/fixtures/heredocs_leading_whitespace.txt
new file mode 100644
index 0000000000..660ecb4543
--- /dev/null
+++ b/test/prism/fixtures/heredocs_leading_whitespace.txt
@@ -0,0 +1,29 @@
+<<-' FOO'
+a
+b
+ FOO
+
+<<-" FOO"
+a
+b
+ FOO
+
+<<-` FOO`
+a
+b
+ FOO
+
+<<-' FOO'
+a
+b
+ FOO
+
+<<~' FOO'
+a
+b
+ FOO
+
+<<~' FOO'
+a
+b
+ FOO
diff --git a/test/prism/fixtures/heredocs_nested.txt b/test/prism/fixtures/heredocs_nested.txt
new file mode 100644
index 0000000000..0802378278
--- /dev/null
+++ b/test/prism/fixtures/heredocs_nested.txt
@@ -0,0 +1,22 @@
+<<~RUBY
+pre
+#{
+<<RUBY
+ hello
+RUBY
+}
+post
+RUBY
+
+# depth greater than PM_LEX_STACK_SIZE
+<<-A
+#{
+<<-B
+#{
+<<-C
+#{3}
+C
+}
+B
+}
+A
diff --git a/test/prism/fixtures/heredocs_with_fake_newlines.txt b/test/prism/fixtures/heredocs_with_fake_newlines.txt
new file mode 100644
index 0000000000..887b7ab5e7
--- /dev/null
+++ b/test/prism/fixtures/heredocs_with_fake_newlines.txt
@@ -0,0 +1,55 @@
+<<-RUBY
+ \n
+ \n
+ exit
+ \\n
+ \n\n\n\n
+ argh
+ \\
+ \\\
+ foo\nbar
+ \f
+ ok
+RUBY
+
+<<~RUBY
+ \n
+ \n
+ exit
+ \\n
+ \n\n\n\n
+ argh
+ \\
+ \\\
+ foo\nbar
+ \f
+ ok
+RUBY
+
+<<~RUBY
+ #{123}\n
+ \n
+ exit
+ \\#{123}n
+ \n#{123}\n\n\n
+ argh
+ \\#{123}baz
+ \\\
+ foo\nbar
+ \f
+ ok
+RUBY
+
+<<'RUBY'
+ \n
+ \n
+ exit
+ \n
+ \n\n\n\n
+ argh
+ \
+ \
+ foo\nbar
+ \f
+ ok
+RUBY
diff --git a/test/prism/fixtures/heredocs_with_ignored_newlines.txt b/test/prism/fixtures/heredocs_with_ignored_newlines.txt
new file mode 100644
index 0000000000..8e12546ec7
--- /dev/null
+++ b/test/prism/fixtures/heredocs_with_ignored_newlines.txt
@@ -0,0 +1,14 @@
+<<-HERE\
+HERE
+
+<<~THERE\
+ way over
+ <<HERE
+ not here
+ HERE
+
+ <<~BUT\
+ but
+ BUT
+ there
+THERE
diff --git a/test/prism/fixtures/heredocs_with_ignored_newlines_and_non_empty.txt b/test/prism/fixtures/heredocs_with_ignored_newlines_and_non_empty.txt
new file mode 100644
index 0000000000..aeacbd8126
--- /dev/null
+++ b/test/prism/fixtures/heredocs_with_ignored_newlines_and_non_empty.txt
@@ -0,0 +1,4 @@
+<<-EOE
+ some
+ heredocs
+EOE \ No newline at end of file
diff --git a/test/prism/fixtures/if.txt b/test/prism/fixtures/if.txt
new file mode 100644
index 0000000000..4139bae5ed
--- /dev/null
+++ b/test/prism/fixtures/if.txt
@@ -0,0 +1,42 @@
+if true; 1; end
+
+if true
+1 else 2 end
+
+if true then true elsif false then false elsif nil then nil else self end
+
+1 if true
+
+tap { break if true }
+
+tap { next if true }
+
+return if true
+
+tap { if exit_loop then break 42 end }
+
+if foo
+then bar
+end
+
+a if b if c
+
+if true
+ a b:
+else
+end
+
+if type in 1
+elsif type in B
+end
+
+if f1
+ lambda do |_|
+ end
+elsif f2
+ lambda do |_|
+ end
+else
+ lambda do |_|
+ end
+end
diff --git a/test/prism/fixtures/indented_file_end.txt b/test/prism/fixtures/indented_file_end.txt
new file mode 100644
index 0000000000..5a96dcacf7
--- /dev/null
+++ b/test/prism/fixtures/indented_file_end.txt
@@ -0,0 +1,4 @@
+ def hi
+
+ end # hi there
+ \ No newline at end of file
diff --git a/test/prism/fixtures/integer_operations.txt b/test/prism/fixtures/integer_operations.txt
new file mode 100644
index 0000000000..37163acf30
--- /dev/null
+++ b/test/prism/fixtures/integer_operations.txt
@@ -0,0 +1,63 @@
+!1
+
+~1
+
+1 != 2
+
+1 !~ 2
+
+1 % 2
+
+1 & 2
+
+1 * 2
+
+1**2
+
+1 + 2
+
+1 - 2
+
+1 / 2
+
+1/2/3
+
+1 < 2
+
+1 << 2
+
+1 <= 2
+
+1 <=> 2
+
+1 == 2
+
+1 === 2
+
+1 =~ 2
+
+1 > 2
+
+1 >= 2
+
+1 >> 2
+
+1 ^ 2
+
+1 | 2
+
+1 && 2
+
+1 and 2
+
+1 * 2 ** 3
+
+1 * 2 + 3
+
+1 or 2
+
+1 || 2
+
+1 + 2 * 3
+
+(1 + 1)
diff --git a/test/prism/fixtures/it_assignment.txt b/test/prism/fixtures/it_assignment.txt
new file mode 100644
index 0000000000..523b0ffe1e
--- /dev/null
+++ b/test/prism/fixtures/it_assignment.txt
@@ -0,0 +1 @@
+42.tap { it = it; p it }
diff --git a/test/prism/fixtures/keyword_method_names.txt b/test/prism/fixtures/keyword_method_names.txt
new file mode 100644
index 0000000000..d3b6eac537
--- /dev/null
+++ b/test/prism/fixtures/keyword_method_names.txt
@@ -0,0 +1,20 @@
+def def
+end
+
+def self.ensure
+end
+
+private def foo
+ bar do
+ end
+end
+
+def m(a, **nil)
+end
+
+%{abc}
+
+%"abc"
+
+def nil::a
+end
diff --git a/test/prism/fixtures/keywords.txt b/test/prism/fixtures/keywords.txt
new file mode 100644
index 0000000000..6d24a9f476
--- /dev/null
+++ b/test/prism/fixtures/keywords.txt
@@ -0,0 +1,11 @@
+tap { redo }
+
+begin; rescue; retry; end
+
+self
+
+__ENCODING__
+
+__FILE__
+
+__LINE__
diff --git a/test/prism/fixtures/lambda.txt b/test/prism/fixtures/lambda.txt
new file mode 100644
index 0000000000..8d67b4dd79
--- /dev/null
+++ b/test/prism/fixtures/lambda.txt
@@ -0,0 +1,27 @@
+->(
+ foo
+) {}
+
+->(x: "b#{a}") { }
+
+->(a: b * 3) {}
+
+-> foo = bar do end
+
+-> foo: bar do end
+
+def foo(*, **)
+ ->() { bar(*, **) }
+end
+
+p{|a:
+b|}
+
+->(a:
+b){}
+
+->a:
+b{}
+
+->a:
+{}
diff --git a/test/prism/fixtures/method_calls.txt b/test/prism/fixtures/method_calls.txt
new file mode 100644
index 0000000000..987fb3f90f
--- /dev/null
+++ b/test/prism/fixtures/method_calls.txt
@@ -0,0 +1,156 @@
+foo.bar %{baz}
+
+a.b(c, d)
+
+a.b()
+
+foo
+ .bar
+ &.baz
+
+a!
+
+a.()
+
+a.(1, 2, 3)
+
+a::b
+
+a::b c
+
+foo.bar = 1
+
+a?
+
+a(&block)
+
+a(**kwargs)
+
+a.b.c
+
+a(b, c)
+
+a()
+
+a(*args)
+
+a b, c
+
+a.b c, d
+
+foo.foo, bar.bar = 1, 2
+
+a&.b
+
+a&.()
+
+a&.b(c)
+
+a&.b()
+
+foo :a, :b if bar? or baz and qux
+
+foo(:a,
+
+ :b
+)
+
+foo(*rest)
+
+foo(:a, :h => [:x, :y], :a => :b, &:bar)
+
+hi 123, { :there => :friend, **{}, whatup: :dog }
+
+foo :a, b: true do |a, b| puts a end
+
+hi there: :friend
+
+hi :there => :friend, **{}, whatup: :dog
+
+hi(:there => :friend, **{}, whatup: :dog)
+
+foo({ a: true, b: false, }, &:block)
+
+hi :there => :friend
+
+foo(:a,
+:b,
+)
+
+foo(
+:a,
+b: :c,
+)
+
+foo &:block
+
+foo a: true, b: false, &:block
+
+some_func 1, kwarg: 2
+
+Kernel.Integer(10)
+
+x.each { }
+
+foo.map { $& }
+
+A::B::C :foo
+
+A::B::C(:foo)
+
+A::B::C(:foo) { }
+
+foo("a": -1)
+
+foo bar: { baz: qux do end }
+
+foo bar: { **kw do end }
+
+foo "#{bar.map do "baz" end}" do end
+
+foo class Bar baz do end end
+
+foo module Bar baz do end end
+
+foo [baz do end]
+
+p begin 1.times do 1 end end
+
+foo :a,
+ if x
+ bar do |a|
+ a
+ end
+ end
+
+foo :a,
+ while x
+ bar do |a|
+ a
+ end
+ end,
+ until x
+ baz do
+ end
+ end
+
+{} + A {}
+
+{} + A { |a| a }
+
+A {} + A {}
+
+lst << A {}
+
+"#{ join (" ") }"
+
+"#{(v)}"
+
+def f(*); p *; end
+
+foo 1, Bar { 1 }
+
+foo = 1
+foo {}
+
+@a.b "c#{name}": 42
diff --git a/test/prism/fixtures/methods.txt b/test/prism/fixtures/methods.txt
new file mode 100644
index 0000000000..eb0a5ca3dc
--- /dev/null
+++ b/test/prism/fixtures/methods.txt
@@ -0,0 +1,190 @@
+def foo((bar, baz))
+end
+
+def foo((bar, baz), optional = 1, (bin, bag))
+end
+
+
+def a; ensure; end
+
+def (b).a
+end
+
+def (a)::b
+end
+
+def false.a
+end
+
+def a(...)
+end
+
+def $var.a
+end
+
+def a.b
+end
+
+def @var.a
+end
+
+def a b:; end
+
+%,abc,
+
+def a(b:)
+end
+
+def a(**b)
+end
+
+def a(**)
+end
+
+a = 1; def a
+end
+
+def a b, c, d
+end
+
+def nil.a
+end
+
+def a b:, c: 1
+end
+
+def a(b:, c: 1)
+end
+
+def a(b:
+ 1, c:)
+end
+
+%.abc.
+
+def a b = 1, c = 2
+end
+
+def a()
+end
+
+def a b, c = 2
+end
+
+def a b
+end
+
+def a; rescue; else; ensure; end
+
+def a *b
+end
+
+def a(*)
+end
+
+def a
+b = 1
+end
+
+def self.a
+end
+
+def true.a
+end
+
+def a
+end
+
+def hi
+return :hi if true
+:bye
+end
+
+def foo = 1
+def bar = 2
+
+def foo(bar) = 123
+
+def foo = 123
+
+def a(*); b(*); end
+
+def a(*, **); b { c(*, **) }; end
+
+def a(...); b(...); end
+
+def a(...); b(1, 2, ...); end
+
+def (c = b).a
+end
+
+def a &b
+end
+
+def a(&)
+end
+
+def @@var.a
+end
+
+def (a = b).C
+end
+
+def self.Array_function; end
+
+Const = 1; def Const.a
+end
+
+def a(...); "foo#{b(...)}"; end
+
+def foo
+ {}.merge **bar, **baz, **qux
+end
+
+def bar(a: (1...10))
+end
+
+def bar(a: (...10))
+end
+
+def bar(a: (1...))
+end
+
+def bar(a = (1...10))
+end
+
+def bar(a = (...10))
+end
+
+def bar(a = (1...))
+end
+
+def method(a)
+ item >> a {}
+end
+
+foo = 1
+def foo.bar; end
+
+def f(*); [*]; end
+
+def f x:-a; end
+
+def f x:+a; end
+
+def f x:!a; end
+
+def foo x:%(xx); end
+
+def foo(...)
+ bar(...)
+end
+
+def foo(bar = (def baz(bar) = bar; 1)) = 2
+
+def (class Foo; end).foo(bar = 1) = 2
+
+module Foo
+ def clone(opts = nil || (return self))
+ end
+end
diff --git a/test/prism/fixtures/modules.txt b/test/prism/fixtures/modules.txt
new file mode 100644
index 0000000000..76bd9bea43
--- /dev/null
+++ b/test/prism/fixtures/modules.txt
@@ -0,0 +1,18 @@
+module A a = 1 end
+
+%Q{aaa #{bbb} ccc}
+
+module m::M
+end
+
+module A
+ x = 1; rescue; end
+
+module ::A
+end
+
+module A[]::B
+end
+
+module A[1]::B
+end
diff --git a/test/prism/fixtures/multi_write.txt b/test/prism/fixtures/multi_write.txt
new file mode 100644
index 0000000000..edbcafb969
--- /dev/null
+++ b/test/prism/fixtures/multi_write.txt
@@ -0,0 +1,4 @@
+foo = 1 rescue nil
+foo, bar = 1 rescue nil
+foo = 1, 2 rescue nil
+foo, bar = 1, 2 rescue nil
diff --git a/test/prism/fixtures/newline_terminated.txt b/test/prism/fixtures/newline_terminated.txt
new file mode 100644
index 0000000000..12f3bda229
--- /dev/null
+++ b/test/prism/fixtures/newline_terminated.txt
Binary files differ
diff --git a/test/prism/fixtures/next.txt b/test/prism/fixtures/next.txt
new file mode 100644
index 0000000000..0d2d6a11f5
--- /dev/null
+++ b/test/prism/fixtures/next.txt
@@ -0,0 +1,28 @@
+tap { next }
+
+tap { next (1), (2), (3) }
+
+tap { next 1 }
+
+tap { next 1, 2,
+3 }
+
+tap { next 1, 2, 3 }
+
+tap { next [1, 2, 3] }
+
+tap { next(
+ 1
+ 2
+) }
+
+tap { next
+1 }
+
+tap { next() }
+
+tap { next(1) }
+
+tap { (next 1) }
+
+tap { foo && (next 1) }
diff --git a/test/prism/fixtures/nils.txt b/test/prism/fixtures/nils.txt
new file mode 100644
index 0000000000..8084db2534
--- /dev/null
+++ b/test/prism/fixtures/nils.txt
@@ -0,0 +1,13 @@
+nil
+
+()
+
+(
+;
+;
+)
+
+END { 1 }
+
+BEGIN { 1 }
+
diff --git a/test/prism/fixtures/non_alphanumeric_methods.txt b/test/prism/fixtures/non_alphanumeric_methods.txt
new file mode 100644
index 0000000000..1da3fd852b
--- /dev/null
+++ b/test/prism/fixtures/non_alphanumeric_methods.txt
@@ -0,0 +1,105 @@
+def !
+end
+
+def !=
+end
+
+def !~
+end
+
+def %
+end
+
+def self.+
+end
+
+def &
+end
+
+def *
+end
+
+def **
+end
+
+%|abc|
+
+def + **b
+end
+
+def +()
+end
+
+def + b
+end
+
+def self.+
+end
+
+def +
+end
+
+def +@
+end
+
+def -
+end
+
+def a.-;end
+
+def -@
+end
+
+def /
+end
+
+def <
+end
+
+def <<
+end
+
+def <=
+end
+
+def <=>
+end
+
+def ==
+end
+
+def ===
+end
+
+def =~
+end
+
+def >
+end
+
+def >=
+end
+
+def >>
+end
+
+def []
+end
+
+def []=
+end
+
+def ^
+end
+
+def `
+end
+
+def self.`
+end
+
+def |
+end
+
+def ~
+end
diff --git a/test/prism/fixtures/non_void_value.txt b/test/prism/fixtures/non_void_value.txt
new file mode 100644
index 0000000000..388e9f2574
--- /dev/null
+++ b/test/prism/fixtures/non_void_value.txt
@@ -0,0 +1,31 @@
+x = begin
+ return if true
+ "conditional"
+end
+
+x = if rand < 0.5
+ return
+ "else is nil"
+end
+
+x = if true
+ return if true
+ "conditional"
+else
+ return
+end
+
+x = if true
+ return if true
+else
+ return if true
+ "conditional"
+end
+
+x = case
+ when 1
+ return if true
+ "conditional"
+ else
+ return
+end
diff --git a/test/prism/fixtures/not.txt b/test/prism/fixtures/not.txt
new file mode 100644
index 0000000000..520b34fa37
--- /dev/null
+++ b/test/prism/fixtures/not.txt
@@ -0,0 +1,37 @@
+not foo and not bar
+
+not(foo and bar)
+
+not foo
+
+not foo and not
+ bar
+
+
+not foo and
+ not
+ bar
+
+
+not foo and
+ not
+
+
+ bar
+
+not(foo
+
+
+)
+
+not(
+
+
+foo
+
+
+ )
+
+not foo .. bar
+
+not (foo .. bar)
diff --git a/test/prism/fixtures/numbers.txt b/test/prism/fixtures/numbers.txt
new file mode 100644
index 0000000000..47f20dcb42
--- /dev/null
+++ b/test/prism/fixtures/numbers.txt
@@ -0,0 +1,67 @@
+0
+
+1
+
+1.0
+
+2
+
+0b0
+
+0b1
+
+0b10
+
+0d0
+
+0d1
+
+0d2
+
+00
+
+01
+
+02
+
+0o0
+
+0o1
+
+0o2
+
+0x0
+
+0x1
+
+0x2
+
+1i
+
+1r
+
+-1
+
+1ri
+
+1.2r
+
+1.2ri
+
+-1ri
+
+-1.2r
+
+-1.2ri
+
+0o1r
+
+0o1i
+
+0o1ri
+
+0d1r
+
+0d1i
+
+0b1ri
diff --git a/test/prism/fixtures/patterns.txt b/test/prism/fixtures/patterns.txt
new file mode 100644
index 0000000000..449dac619b
--- /dev/null
+++ b/test/prism/fixtures/patterns.txt
@@ -0,0 +1,224 @@
+foo => bar
+foo => 1
+foo => 1.0
+foo => 1i
+foo => 1r
+foo => :foo
+foo => %s[foo]
+foo => :"foo"
+foo => /foo/
+foo => `foo`
+foo => %x[foo]
+foo => %i[foo]
+foo => %I[foo]
+foo => %w[foo]
+foo => %W[foo]
+foo => %q[foo]
+foo => %Q[foo]
+foo => "foo"
+foo => nil
+foo => self
+foo => true
+foo => false
+foo => __FILE__
+foo => __LINE__
+foo => __ENCODING__
+foo => -> { bar }
+
+foo => 1 .. 1
+foo => 1.0 .. 1.0
+foo => 1i .. 1i
+foo => 1r .. 1r
+foo => :foo .. :foo
+foo => %s[foo] .. %s[foo]
+foo => :"foo" .. :"foo"
+foo => /foo/ .. /foo/
+foo => `foo` .. `foo`
+foo => %x[foo] .. %x[foo]
+foo => %i[foo] .. %i[foo]
+foo => %I[foo] .. %I[foo]
+foo => %w[foo] .. %w[foo]
+foo => %W[foo] .. %W[foo]
+foo => %q[foo] .. %q[foo]
+foo => %Q[foo] .. %Q[foo]
+foo => "foo" .. "foo"
+foo => nil .. nil
+foo => self .. self
+foo => true .. true
+foo => false .. false
+foo => __FILE__ .. __FILE__
+foo => __LINE__ .. __LINE__
+foo => __ENCODING__ .. __ENCODING__
+foo => -> { bar } .. -> { bar }
+
+bar = 1; foo => ^bar
+foo => ^@bar
+foo => ^@@bar
+foo => ^$bar
+
+foo => ^(1)
+foo => ^(nil)
+foo => ^("bar" + "baz")
+
+foo => Foo
+foo => Foo::Bar::Baz
+foo => ::Foo
+foo => ::Foo::Bar::Baz
+
+foo => Foo()
+foo => Foo(1)
+foo => Foo(1, 2, 3)
+foo => Foo(bar)
+foo => Foo(*bar, baz)
+foo => Foo(bar, *baz)
+foo => Foo(*bar, baz, *qux)
+
+foo => Foo[]
+foo => Foo[1]
+foo => Foo[1, 2, 3]
+foo => Foo[Foo[]]
+foo => Foo[bar]
+foo => Foo[*bar, baz]
+foo => Foo[bar, *baz]
+foo => Foo[*bar, baz, *qux]
+
+foo => *bar
+foo => *bar, baz, qux
+foo => bar, *baz, qux
+foo => bar, baz, *qux
+foo => *bar, baz, *qux
+foo => bar,;
+
+foo => []
+foo => [[[[[]]]]]
+
+foo => [*bar]
+foo => [*bar, baz, qux]
+foo => [bar, *baz, qux]
+foo => [bar, baz, *qux]
+foo => [*bar, baz, *qux]
+
+foo in bar
+foo in 1
+foo in 1.0
+foo in 1i
+foo in 1r
+foo in :foo
+foo in %s[foo]
+foo in :"foo"
+foo in /foo/
+foo in `foo`
+foo in %x[foo]
+foo in %i[foo]
+foo in %I[foo]
+foo in %w[foo]
+foo in %W[foo]
+foo in %q[foo]
+foo in %Q[foo]
+foo in "foo"
+foo in nil
+foo in self
+foo in true
+foo in false
+foo in __FILE__
+foo in __LINE__
+foo in __ENCODING__
+foo in -> { bar }
+foo in bar,;
+
+case foo; in bar then end
+case foo; in 1 then end
+case foo; in 1.0 then end
+case foo; in 1i then end
+case foo; in 1r then end
+case foo; in :foo then end
+case foo; in %s[foo] then end
+case foo; in :"foo" then end
+case foo; in /foo/ then end
+case foo; in `foo` then end
+case foo; in %x[foo] then end
+case foo; in %i[foo] then end
+case foo; in %I[foo] then end
+case foo; in %w[foo] then end
+case foo; in %W[foo] then end
+case foo; in %q[foo] then end
+case foo; in %Q[foo] then end
+case foo; in "foo" then end
+case foo; in nil then end
+case foo; in self then end
+case foo; in true then end
+case foo; in false then end
+case foo; in __FILE__ then end
+case foo; in __LINE__ then end
+case foo; in __ENCODING__ then end
+case foo; in -> { bar } then end
+
+case foo; in bar if baz then end
+case foo; in 1 if baz then end
+case foo; in 1.0 if baz then end
+case foo; in 1i if baz then end
+case foo; in 1r if baz then end
+case foo; in :foo if baz then end
+case foo; in %s[foo] if baz then end
+case foo; in :"foo" if baz then end
+case foo; in /foo/ if baz then end
+case foo; in `foo` if baz then end
+case foo; in %x[foo] if baz then end
+case foo; in %i[foo] if baz then end
+case foo; in %I[foo] if baz then end
+case foo; in %w[foo] if baz then end
+case foo; in %W[foo] if baz then end
+case foo; in %q[foo] if baz then end
+case foo; in %Q[foo] if baz then end
+case foo; in "foo" if baz then end
+case foo; in nil if baz then end
+case foo; in self if baz then end
+case foo; in true if baz then end
+case foo; in false if baz then end
+case foo; in __FILE__ if baz then end
+case foo; in __LINE__ if baz then end
+case foo; in __ENCODING__ if baz then end
+case foo; in -> { bar } if baz then end
+
+if a in []
+end
+
+a => [
+ b
+]
+
+foo in A[
+ bar: B[
+ value: a
+ ]
+]
+
+foo in bar => baz
+foo => bar => baz
+
+foo, bar, baz = 1, 2
+foo do
+ [1, 2] => [foo, bar] => baz
+end
+
+foo => Object[{x:}]
+
+1.then { 1 in ^_1 }
+
+(
+ a,
+ b
+) = c
+
+case (); in [_a, _a]; end
+case (); in [{a:1}, {a:2}]; end
+a => ^({'a' => 'b'})
+
+a in b, and c
+a in b, or c
+(a in b,) and c
+(a in b,) or c
+
+x => ^([*a.x])
+x => ^([**a.x])
+x => ^({ a: })
diff --git a/test/prism/fixtures/procs.txt b/test/prism/fixtures/procs.txt
new file mode 100644
index 0000000000..7ffb11e78a
--- /dev/null
+++ b/test/prism/fixtures/procs.txt
@@ -0,0 +1,27 @@
+-> (a; b, c, d) { b }
+
+-> do
+ensure
+end
+
+-> do
+rescue
+else
+ensure
+end
+
+-> { foo }
+
+-> do; foo; end
+
+-> a, b = 1, c:, d:, &e { a }
+
+-> (a, b = 1, *c, d:, e:, **f, &g) { a }
+
+-> (a, b = 1, *c, d:, e:, **f, &g) do
+ a
+end
+
+-> (a) { -> b { a * b } }
+
+-> ((a, b), *c) { }
diff --git a/test/prism/fixtures/range_begin_open_exclusive.txt b/test/prism/fixtures/range_begin_open_exclusive.txt
new file mode 100644
index 0000000000..3b12672b4f
--- /dev/null
+++ b/test/prism/fixtures/range_begin_open_exclusive.txt
@@ -0,0 +1 @@
+...2
diff --git a/test/prism/fixtures/range_begin_open_inclusive.txt b/test/prism/fixtures/range_begin_open_inclusive.txt
new file mode 100644
index 0000000000..052f45900b
--- /dev/null
+++ b/test/prism/fixtures/range_begin_open_inclusive.txt
@@ -0,0 +1 @@
+..2
diff --git a/test/prism/fixtures/range_beginless.txt b/test/prism/fixtures/range_beginless.txt
new file mode 100644
index 0000000000..a55b9b57e7
--- /dev/null
+++ b/test/prism/fixtures/range_beginless.txt
@@ -0,0 +1,5 @@
+def f(x = ...?a); end
+
+def f(x: ...?a); end
+
+def f() ...:a; end
diff --git a/test/prism/fixtures/range_end_open_exclusive.txt b/test/prism/fixtures/range_end_open_exclusive.txt
new file mode 100644
index 0000000000..2ffd68afdb
--- /dev/null
+++ b/test/prism/fixtures/range_end_open_exclusive.txt
@@ -0,0 +1 @@
+2...
diff --git a/test/prism/fixtures/range_end_open_inclusive.txt b/test/prism/fixtures/range_end_open_inclusive.txt
new file mode 100644
index 0000000000..48445391f6
--- /dev/null
+++ b/test/prism/fixtures/range_end_open_inclusive.txt
@@ -0,0 +1 @@
+2..
diff --git a/test/prism/fixtures/ranges.txt b/test/prism/fixtures/ranges.txt
new file mode 100644
index 0000000000..87eac6d241
--- /dev/null
+++ b/test/prism/fixtures/ranges.txt
@@ -0,0 +1,51 @@
+(...2)
+
+(..2)
+
+foo ((1..1))
+
+1...2
+
+foo[...2]
+
+{ foo: ...bar }
+
+(1...)
+
+1..2
+
+{ foo: ..bar }
+
+(1..)
+
+1 .. ..1
+
+1.. && 2
+
+1.. == 2
+
+1.. != 2
+
+1.. === 2
+
+1.. <=> 2
+
+1.. =~ 2
+
+1.. !~ 2
+
+1.. < 2
+
+1.. > 2
+
+1.. <= 2
+
+1.. >= 2
+
+1.. << 2
+
+1.. >> 2
+
+1.. + 2
+
+1.. - 2
diff --git a/test/prism/fixtures/regex.txt b/test/prism/fixtures/regex.txt
new file mode 100644
index 0000000000..712bfc081a
--- /dev/null
+++ b/test/prism/fixtures/regex.txt
@@ -0,0 +1,58 @@
+foo /bar/
+
+%r{abc}i
+
+/a\b/
+
+/aaa #$bbb/
+
+/aaa #{bbb} ccc/
+
+[/(?<foo>bar)/ =~ baz, foo]
+
+/abc/i
+
+%r/[a-z$._?][\w$.?#@~]*:/i
+
+%r/([a-z$._?][\w$.?#@~]*)(\s+)(equ)/i
+
+%r/[a-z$._?][\w$.?#@~]*/i
+
+%r(
+(?:[#$%_']|\(\)|\(,\)|\[\]|[0-9])*
+ (?:[#$%_']+)
+)
+
+/(?#\))/ =~ "hi"
+
+%r#pound#
+
+/aaa #{bbb}/o
+
+/(?<a\
+b>)/ =~ ""; ab
+
+/(?<abc>)(?<abc>)/ =~ ""; abc
+
+/(?<a b>)/ =~ ""
+
+a = 1
+tap { /(?<a>)/ =~ to_s }
+
+/(?<foo>)/ =~ ""
+/(?<Foo>)/ =~ ""
+
+/(?<nil>)/ =~ ""
+def foo(nil:) = /(?<nil>)/ =~ ""
+
+/(?-x:#)/x
+
+/a
+b\
+c\
+d\\\
+e\\
+f\
+/
+
+//
diff --git a/test/prism/fixtures/regex_char_width.txt b/test/prism/fixtures/regex_char_width.txt
new file mode 100644
index 0000000000..7096b71584
--- /dev/null
+++ b/test/prism/fixtures/regex_char_width.txt
@@ -0,0 +1,3 @@
+# encoding: sjis
+/Ⅷ(?<a>.)Ⅹ(?<b>.)/ =~ 'ⅧaⅩb'
+[a, b]
diff --git a/test/prism/fixtures/regex_escape_encoding.txt b/test/prism/fixtures/regex_escape_encoding.txt
new file mode 100644
index 0000000000..74e1647d67
--- /dev/null
+++ b/test/prism/fixtures/regex_escape_encoding.txt
@@ -0,0 +1,3 @@
+# encoding: US-ASCII
+str = "hello \xFC"
+str =~ /hello \u{fc}/
diff --git a/test/prism/fixtures/regex_with_fake_newlines.txt b/test/prism/fixtures/regex_with_fake_newlines.txt
new file mode 100644
index 0000000000..d92a2e4ade
--- /dev/null
+++ b/test/prism/fixtures/regex_with_fake_newlines.txt
@@ -0,0 +1,41 @@
+/
+ \n
+ \n
+ exit
+ \\n
+ \n\n\n\n
+ argh
+ \\
+ \\\
+ foo\nbar
+ \f
+ ok
+/
+
+%r{
+ \n
+ \n
+ exit
+ \\n
+ \n\n\n\n
+ argh
+ \\
+ \\\
+ foo\nbar
+ \f
+ ok
+}
+
+%r{
+ #{123}\n
+ \n
+ exit\\\
+ \\#{123}n
+ \n#{123}\n\n\n
+ argh\
+ \\#{123}baz\\
+ \\\
+ foo\nbar
+ \f
+ ok
+}
diff --git a/test/prism/fixtures/repeat_parameters.txt b/test/prism/fixtures/repeat_parameters.txt
new file mode 100644
index 0000000000..9c69e9718a
--- /dev/null
+++ b/test/prism/fixtures/repeat_parameters.txt
@@ -0,0 +1,38 @@
+def foo(a, _)
+end
+
+def foo(a, _, _)
+end
+
+def foo(a, _, _, _b)
+end
+
+def foo(a, _, _, _b, _b)
+end
+
+def foo(a, (b, *_c, d), (e, *_c, f))
+end
+
+def foo(_a, _a, b, c)
+end
+
+def foo((a, *_b, c), (d, *_b, e))
+end
+
+def foo(_a = 1, _a = 2)
+end
+
+def foo(_a:, _a:)
+end
+
+def foo(_a: 1, _a: 2)
+end
+
+def foo(_a, **_a)
+end
+
+def foo(_a, &_a)
+end
+
+def foo(_a, *_a)
+end
diff --git a/test/prism/fixtures/rescue.txt b/test/prism/fixtures/rescue.txt
new file mode 100644
index 0000000000..f436463029
--- /dev/null
+++ b/test/prism/fixtures/rescue.txt
@@ -0,0 +1,39 @@
+foo rescue nil
+
+foo rescue
+nil
+
+tap { break rescue nil }
+
+tap { next rescue nil }
+
+return rescue nil
+
+foo rescue nil || 1
+
+foo rescue nil ? 1 : 2
+
+begin; a; rescue *b; end
+
+foo do |x|
+ bar(y) rescue ArgumentError fail "baz"
+end
+
+if a = foo rescue nil
+ bar
+end
+
+def some_method = other_method 42 rescue nil
+
+def a
+ a b:
+rescue
+end
+
+foo if bar rescue baz
+
+z = x y rescue c d
+
+begin
+rescue => A[]
+end
diff --git a/test/prism/fixtures/rescue_modifier.txt b/test/prism/fixtures/rescue_modifier.txt
new file mode 100644
index 0000000000..def9e2dbed
--- /dev/null
+++ b/test/prism/fixtures/rescue_modifier.txt
@@ -0,0 +1,7 @@
+a rescue b if c
+
+a = b rescue c if d
+
+a, = b rescue c if d
+
+def a = b rescue c if d
diff --git a/test/prism/fixtures/return.txt b/test/prism/fixtures/return.txt
new file mode 100644
index 0000000000..952fb80da8
--- /dev/null
+++ b/test/prism/fixtures/return.txt
@@ -0,0 +1,27 @@
+return
+
+return (1), (2), (3)
+
+return *1
+
+return 1
+
+return 1, 2,
+3
+
+return 1, 2, 3
+
+return [1, 2, 3]
+
+return(
+ 1
+ 2
+)
+
+return()
+
+return(1)
+
+(return 1)
+
+foo && (return 1)
diff --git a/test/prism/fixtures/seattlerb/BEGIN.txt b/test/prism/fixtures/seattlerb/BEGIN.txt
new file mode 100644
index 0000000000..bed5755901
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/BEGIN.txt
@@ -0,0 +1 @@
+BEGIN { 42 }
diff --git a/test/prism/fixtures/seattlerb/README.rdoc b/test/prism/fixtures/seattlerb/README.rdoc
new file mode 100644
index 0000000000..1e5bfbdfe0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/README.rdoc
@@ -0,0 +1,113 @@
+= ruby_parser
+
+home :: https://github.com/seattlerb/ruby_parser
+bugs :: https://github.com/seattlerb/ruby_parser/issues
+rdoc :: http://docs.seattlerb.org/ruby_parser
+
+== DESCRIPTION:
+
+ruby_parser (RP) is a ruby parser written in pure ruby (utilizing
+racc--which does by default use a C extension). It outputs
+s-expressions which can be manipulated and converted back to ruby via
+the ruby2ruby gem.
+
+As an example:
+
+ def conditional1 arg1
+ return 1 if arg1 == 0
+ return 0
+ end
+
+becomes:
+
+ s(:defn, :conditional1, s(:args, :arg1),
+ s(:if,
+ s(:call, s(:lvar, :arg1), :==, s(:lit, 0)),
+ s(:return, s(:lit, 1)),
+ nil),
+ s(:return, s(:lit, 0)))
+
+Tested against 801,039 files from the latest of all rubygems (as of 2013-05):
+
+* 1.8 parser is at 99.9739% accuracy, 3.651 sigma
+* 1.9 parser is at 99.9940% accuracy, 4.013 sigma
+* 2.0 parser is at 99.9939% accuracy, 4.008 sigma
+* 2.6 parser is at 99.9972% accuracy, 4.191 sigma
+* 3.0 parser has a 100% parse rate.
+ * Tested against 2,672,412 unique ruby files across 167k gems.
+ * As do all the others now, basically.
+
+== FEATURES/PROBLEMS:
+
+* Pure ruby, no compiles.
+* Includes preceding comment data for defn/defs/class/module nodes!
+* Incredibly simple interface.
+* Output is 100% equivalent to ParseTree.
+ * Can utilize PT's SexpProcessor and UnifiedRuby for language processing.
+* Known Issue: Speed is now pretty good, but can always improve:
+ * RP parses a corpus of 3702 files in 125s (avg 108 Kb/s)
+ * MRI+PT parsed the same in 67.38s (avg 200.89 Kb/s)
+* Known Issue: Code is much better, but still has a long way to go.
+* Known Issue: Totally awesome.
+* Known Issue: line number values can be slightly off. Parsing LR sucks.
+
+== SYNOPSIS:
+
+ RubyParser.new.parse "1+1"
+ # => s(:call, s(:lit, 1), :+, s(:lit, 1))
+
+You can also use Ruby19Parser, Ruby18Parser, or RubyParser.for_current_ruby:
+
+ RubyParser.for_current_ruby.parse "1+1"
+ # => s(:call, s(:lit, 1), :+, s(:lit, 1))
+
+== DEVELOPER NOTES:
+
+To add a new version:
+
+* New parser should be generated from lib/ruby_parser[23].yy.
+* Extend lib/ruby_parser[23].yy with new class name.
+* Add new version number to V2/V3 in Rakefile for rule creation.
+* Add new `ruby_parse "x.y.z"` line to Rakefile for rake compare (line ~300).
+* Require generated parser in lib/ruby_parser.rb.
+* Add new V## = ::Ruby##Parser; end to ruby_parser.rb (bottom of file).
+* Add empty TestRubyParserShared##Plus module and TestRubyParserV## to test/test_ruby_parser.rb.
+* Extend Manifest.txt with generated file names.
+* Add new version number to sexp_processor's pt_testcase.rb in all_versions.
+
+Until all of these are done, you won't have a clean test run.
+
+== REQUIREMENTS:
+
+* ruby. woot.
+* sexp_processor for Sexp and SexpProcessor classes, and testing.
+* racc full package for parser development (compiling .y to .rb).
+
+== INSTALL:
+
+* sudo gem install ruby_parser
+
+== LICENSE:
+
+(The MIT License)
+
+Copyright (c) Ryan Davis, seattle.rb
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/test/prism/fixtures/seattlerb/TestRubyParserShared.txt b/test/prism/fixtures/seattlerb/TestRubyParserShared.txt
new file mode 100644
index 0000000000..c55b3e1f70
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/TestRubyParserShared.txt
@@ -0,0 +1,92 @@
+%I[
+
+
+]
+
+%I[
+line2
+line3
+]
+
+%W[
+
+
+]
+
+%W[
+line2
+line3
+]
+
+%i[
+
+
+]
+
+%i[
+line2
+line3
+]
+
+%r[
+
+
+]
+
+%w[
+
+
+]
+
+%w[
+line2
+line3
+]
+
+[
+:line2,
+:line3
+]
+
+class X # line 1
+ def self.y(a, # line 2
+ b) # line 3
+ a + b # line 4
+ end # line 5
+end # line 6
+
+
+class X # line 1
+ class Y # line 2
+ Z = 42 # line 3
+ end # line 4
+end # line 5
+
+
+class X # line 1
+ def y(a, # line 2
+ b) # line 3
+ a + b # line 4
+ end # line 5
+end # line 6
+
+
+module X
+ X = [
+ :line3,
+ :line4,
+ ]
+end
+
+
+module X # line 1
+ module Y # line 2
+ Z = 42 # line 3
+ end # line 4
+end # line 5
+
+
+x(
+:line2,
+:line3
+)
diff --git a/test/prism/fixtures/seattlerb/__ENCODING__.txt b/test/prism/fixtures/seattlerb/__ENCODING__.txt
new file mode 100644
index 0000000000..d6debf2f92
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/__ENCODING__.txt
@@ -0,0 +1 @@
+__ENCODING__
diff --git a/test/prism/fixtures/seattlerb/alias_gvar_backref.txt b/test/prism/fixtures/seattlerb/alias_gvar_backref.txt
new file mode 100644
index 0000000000..016bd94fe0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/alias_gvar_backref.txt
@@ -0,0 +1 @@
+alias $MATCH $&
diff --git a/test/prism/fixtures/seattlerb/alias_resword.txt b/test/prism/fixtures/seattlerb/alias_resword.txt
new file mode 100644
index 0000000000..63e782614b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/alias_resword.txt
@@ -0,0 +1 @@
+alias in out
diff --git a/test/prism/fixtures/seattlerb/and_multi.txt b/test/prism/fixtures/seattlerb/and_multi.txt
new file mode 100644
index 0000000000..8902086cac
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/and_multi.txt
@@ -0,0 +1,3 @@
+true and
+not false and
+true
diff --git a/test/prism/fixtures/seattlerb/aref_args_assocs.txt b/test/prism/fixtures/seattlerb/aref_args_assocs.txt
new file mode 100644
index 0000000000..3244eebafc
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/aref_args_assocs.txt
@@ -0,0 +1 @@
+[1 => 2]
diff --git a/test/prism/fixtures/seattlerb/aref_args_lit_assocs.txt b/test/prism/fixtures/seattlerb/aref_args_lit_assocs.txt
new file mode 100644
index 0000000000..0b6ffa7e2c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/aref_args_lit_assocs.txt
@@ -0,0 +1 @@
+[1, 2 => 3]
diff --git a/test/prism/fixtures/seattlerb/args_kw_block.txt b/test/prism/fixtures/seattlerb/args_kw_block.txt
new file mode 100644
index 0000000000..cb6ab39852
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/args_kw_block.txt
@@ -0,0 +1 @@
+def f(a: 1, &b); end
diff --git a/test/prism/fixtures/seattlerb/array_line_breaks.txt b/test/prism/fixtures/seattlerb/array_line_breaks.txt
new file mode 100644
index 0000000000..be9f2d9cb8
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/array_line_breaks.txt
@@ -0,0 +1,4 @@
+[
+'a',
+'b']
+1
diff --git a/test/prism/fixtures/seattlerb/array_lits_trailing_calls.txt b/test/prism/fixtures/seattlerb/array_lits_trailing_calls.txt
new file mode 100644
index 0000000000..868384a407
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/array_lits_trailing_calls.txt
@@ -0,0 +1,3 @@
+%w[].b
+
+[].b
diff --git a/test/prism/fixtures/seattlerb/assoc__bare.txt b/test/prism/fixtures/seattlerb/assoc__bare.txt
new file mode 100644
index 0000000000..96c2940f31
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/assoc__bare.txt
@@ -0,0 +1 @@
+{ y: }
diff --git a/test/prism/fixtures/seattlerb/assoc_label.txt b/test/prism/fixtures/seattlerb/assoc_label.txt
new file mode 100644
index 0000000000..372dc75031
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/assoc_label.txt
@@ -0,0 +1 @@
+a(b:1)
diff --git a/test/prism/fixtures/seattlerb/attr_asgn_colon_id.txt b/test/prism/fixtures/seattlerb/attr_asgn_colon_id.txt
new file mode 100644
index 0000000000..f63c2f5dcb
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/attr_asgn_colon_id.txt
@@ -0,0 +1 @@
+A::b = 1
diff --git a/test/prism/fixtures/seattlerb/attrasgn_array_arg.txt b/test/prism/fixtures/seattlerb/attrasgn_array_arg.txt
new file mode 100644
index 0000000000..db9e2db063
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/attrasgn_array_arg.txt
@@ -0,0 +1 @@
+a[[1, 2]] = 3
diff --git a/test/prism/fixtures/seattlerb/attrasgn_array_lhs.txt b/test/prism/fixtures/seattlerb/attrasgn_array_lhs.txt
new file mode 100644
index 0000000000..0b8e31632d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/attrasgn_array_lhs.txt
@@ -0,0 +1 @@
+[1, 2, 3, 4][from .. to] = ["a", "b", "c"]
diff --git a/test/prism/fixtures/seattlerb/attrasgn_primary_dot_constant.txt b/test/prism/fixtures/seattlerb/attrasgn_primary_dot_constant.txt
new file mode 100644
index 0000000000..380a718963
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/attrasgn_primary_dot_constant.txt
@@ -0,0 +1 @@
+a.B = 1
diff --git a/test/prism/fixtures/seattlerb/backticks_interpolation_line.txt b/test/prism/fixtures/seattlerb/backticks_interpolation_line.txt
new file mode 100644
index 0000000000..b3ba31c72a
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/backticks_interpolation_line.txt
@@ -0,0 +1 @@
+x `#{y}`
diff --git a/test/prism/fixtures/seattlerb/bang_eq.txt b/test/prism/fixtures/seattlerb/bang_eq.txt
new file mode 100644
index 0000000000..0283460e46
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bang_eq.txt
@@ -0,0 +1 @@
+1 != 2
diff --git a/test/prism/fixtures/seattlerb/bdot2.txt b/test/prism/fixtures/seattlerb/bdot2.txt
new file mode 100644
index 0000000000..4fb2692299
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bdot2.txt
@@ -0,0 +1,3 @@
+..10
+; ..a
+; c
diff --git a/test/prism/fixtures/seattlerb/bdot3.txt b/test/prism/fixtures/seattlerb/bdot3.txt
new file mode 100644
index 0000000000..8079cf9872
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bdot3.txt
@@ -0,0 +1,3 @@
+...10
+; ...a
+; c
diff --git a/test/prism/fixtures/seattlerb/begin_ensure_no_bodies.txt b/test/prism/fixtures/seattlerb/begin_ensure_no_bodies.txt
new file mode 100644
index 0000000000..51dde02ea3
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/begin_ensure_no_bodies.txt
@@ -0,0 +1,3 @@
+begin
+ensure
+end
diff --git a/test/prism/fixtures/seattlerb/begin_rescue_else_ensure_bodies.txt b/test/prism/fixtures/seattlerb/begin_rescue_else_ensure_bodies.txt
new file mode 100644
index 0000000000..ae6e2c3636
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/begin_rescue_else_ensure_bodies.txt
@@ -0,0 +1,9 @@
+begin
+ 1
+rescue
+ 2
+else
+ 3
+ensure
+ 4
+end
diff --git a/test/prism/fixtures/seattlerb/begin_rescue_else_ensure_no_bodies.txt b/test/prism/fixtures/seattlerb/begin_rescue_else_ensure_no_bodies.txt
new file mode 100644
index 0000000000..456d9a5d6e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/begin_rescue_else_ensure_no_bodies.txt
@@ -0,0 +1,9 @@
+begin
+
+rescue
+
+else
+
+ensure
+
+end
diff --git a/test/prism/fixtures/seattlerb/begin_rescue_ensure_no_bodies.txt b/test/prism/fixtures/seattlerb/begin_rescue_ensure_no_bodies.txt
new file mode 100644
index 0000000000..896e3c030a
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/begin_rescue_ensure_no_bodies.txt
@@ -0,0 +1,4 @@
+begin
+rescue
+ensure
+end
diff --git a/test/prism/fixtures/seattlerb/block_arg__bare.txt b/test/prism/fixtures/seattlerb/block_arg__bare.txt
new file mode 100644
index 0000000000..6454b00345
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_arg__bare.txt
@@ -0,0 +1 @@
+def x(&); end
diff --git a/test/prism/fixtures/seattlerb/block_arg_kwsplat.txt b/test/prism/fixtures/seattlerb/block_arg_kwsplat.txt
new file mode 100644
index 0000000000..a9c255cc66
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_arg_kwsplat.txt
@@ -0,0 +1 @@
+a { |**b| }
diff --git a/test/prism/fixtures/seattlerb/block_arg_opt_arg_block.txt b/test/prism/fixtures/seattlerb/block_arg_opt_arg_block.txt
new file mode 100644
index 0000000000..14cb02c68e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_arg_opt_arg_block.txt
@@ -0,0 +1 @@
+a { |b, c=1, d, &e| }
diff --git a/test/prism/fixtures/seattlerb/block_arg_opt_splat.txt b/test/prism/fixtures/seattlerb/block_arg_opt_splat.txt
new file mode 100644
index 0000000000..a077ae1f34
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_arg_opt_splat.txt
@@ -0,0 +1 @@
+a { |b, c = 1, *d| }
diff --git a/test/prism/fixtures/seattlerb/block_arg_opt_splat_arg_block_omfg.txt b/test/prism/fixtures/seattlerb/block_arg_opt_splat_arg_block_omfg.txt
new file mode 100644
index 0000000000..5016a7c6b9
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_arg_opt_splat_arg_block_omfg.txt
@@ -0,0 +1 @@
+a { |b, c=1, *d, e, &f| }
diff --git a/test/prism/fixtures/seattlerb/block_arg_optional.txt b/test/prism/fixtures/seattlerb/block_arg_optional.txt
new file mode 100644
index 0000000000..966afc5640
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_arg_optional.txt
@@ -0,0 +1 @@
+a { |b = 1| }
diff --git a/test/prism/fixtures/seattlerb/block_arg_scope.txt b/test/prism/fixtures/seattlerb/block_arg_scope.txt
new file mode 100644
index 0000000000..2362e08559
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_arg_scope.txt
@@ -0,0 +1 @@
+a { |b; c| }
diff --git a/test/prism/fixtures/seattlerb/block_arg_scope2.txt b/test/prism/fixtures/seattlerb/block_arg_scope2.txt
new file mode 100644
index 0000000000..f7222dc7b1
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_arg_scope2.txt
@@ -0,0 +1 @@
+a {|b; c, d| }
diff --git a/test/prism/fixtures/seattlerb/block_arg_splat_arg.txt b/test/prism/fixtures/seattlerb/block_arg_splat_arg.txt
new file mode 100644
index 0000000000..d7c31aae6b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_arg_splat_arg.txt
@@ -0,0 +1 @@
+a { |b, *c, d| }
diff --git a/test/prism/fixtures/seattlerb/block_args_kwargs.txt b/test/prism/fixtures/seattlerb/block_args_kwargs.txt
new file mode 100644
index 0000000000..467b577a7e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_args_kwargs.txt
@@ -0,0 +1 @@
+f { |**kwargs| kwargs }
diff --git a/test/prism/fixtures/seattlerb/block_args_no_kwargs.txt b/test/prism/fixtures/seattlerb/block_args_no_kwargs.txt
new file mode 100644
index 0000000000..5c9bfa3a62
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_args_no_kwargs.txt
@@ -0,0 +1 @@
+f { |**nil| }
diff --git a/test/prism/fixtures/seattlerb/block_args_opt1.txt b/test/prism/fixtures/seattlerb/block_args_opt1.txt
new file mode 100644
index 0000000000..372689e36a
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_args_opt1.txt
@@ -0,0 +1 @@
+f { |a, b = 42| [a, b] }
diff --git a/test/prism/fixtures/seattlerb/block_args_opt2.txt b/test/prism/fixtures/seattlerb/block_args_opt2.txt
new file mode 100644
index 0000000000..10d0746646
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_args_opt2.txt
@@ -0,0 +1 @@
+a { | b=1, c=2 | }
diff --git a/test/prism/fixtures/seattlerb/block_args_opt2_2.txt b/test/prism/fixtures/seattlerb/block_args_opt2_2.txt
new file mode 100644
index 0000000000..563a9bf915
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_args_opt2_2.txt
@@ -0,0 +1 @@
+f { |a, b = 42, c = 24| [a, b, c] }
diff --git a/test/prism/fixtures/seattlerb/block_args_opt3.txt b/test/prism/fixtures/seattlerb/block_args_opt3.txt
new file mode 100644
index 0000000000..bb5a7c8458
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_args_opt3.txt
@@ -0,0 +1 @@
+f { |a, b = 42, c = 24, &d| [a, b, c, d] }
diff --git a/test/prism/fixtures/seattlerb/block_call_defn_call_block_call.txt b/test/prism/fixtures/seattlerb/block_call_defn_call_block_call.txt
new file mode 100644
index 0000000000..ff1b3a4c9f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_call_defn_call_block_call.txt
@@ -0,0 +1,4 @@
+a def b(c)
+ d
+ end
+ e.f do end
diff --git a/test/prism/fixtures/seattlerb/block_call_dot_op2_brace_block.txt b/test/prism/fixtures/seattlerb/block_call_dot_op2_brace_block.txt
new file mode 100644
index 0000000000..63da9ee7af
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_call_dot_op2_brace_block.txt
@@ -0,0 +1 @@
+a.b c() do d end.e do |f| g end
diff --git a/test/prism/fixtures/seattlerb/block_call_dot_op2_cmd_args_do_block.txt b/test/prism/fixtures/seattlerb/block_call_dot_op2_cmd_args_do_block.txt
new file mode 100644
index 0000000000..24e7d0f1f1
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_call_dot_op2_cmd_args_do_block.txt
@@ -0,0 +1 @@
+a.b c() do d end.e f do |g| h end
diff --git a/test/prism/fixtures/seattlerb/block_call_operation_colon.txt b/test/prism/fixtures/seattlerb/block_call_operation_colon.txt
new file mode 100644
index 0000000000..593b9e1bc0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_call_operation_colon.txt
@@ -0,0 +1 @@
+a.b c do end::d
diff --git a/test/prism/fixtures/seattlerb/block_call_operation_dot.txt b/test/prism/fixtures/seattlerb/block_call_operation_dot.txt
new file mode 100644
index 0000000000..20b8e4fcb8
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_call_operation_dot.txt
@@ -0,0 +1 @@
+a.b c do end.d
diff --git a/test/prism/fixtures/seattlerb/block_call_paren_call_block_call.txt b/test/prism/fixtures/seattlerb/block_call_paren_call_block_call.txt
new file mode 100644
index 0000000000..7f8be95100
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_call_paren_call_block_call.txt
@@ -0,0 +1,2 @@
+a (b)
+c.d do end
diff --git a/test/prism/fixtures/seattlerb/block_command_operation_colon.txt b/test/prism/fixtures/seattlerb/block_command_operation_colon.txt
new file mode 100644
index 0000000000..db221ad496
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_command_operation_colon.txt
@@ -0,0 +1 @@
+a :b do end::c :d
diff --git a/test/prism/fixtures/seattlerb/block_command_operation_dot.txt b/test/prism/fixtures/seattlerb/block_command_operation_dot.txt
new file mode 100644
index 0000000000..56b71677e8
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_command_operation_dot.txt
@@ -0,0 +1 @@
+a :b do end.c :d
diff --git a/test/prism/fixtures/seattlerb/block_decomp_anon_splat_arg.txt b/test/prism/fixtures/seattlerb/block_decomp_anon_splat_arg.txt
new file mode 100644
index 0000000000..96f5d5d2ec
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_decomp_anon_splat_arg.txt
@@ -0,0 +1 @@
+f { |(*, a)| }
diff --git a/test/prism/fixtures/seattlerb/block_decomp_arg_splat.txt b/test/prism/fixtures/seattlerb/block_decomp_arg_splat.txt
new file mode 100644
index 0000000000..f8db3874de
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_decomp_arg_splat.txt
@@ -0,0 +1 @@
+a { |(b, *)| }
diff --git a/test/prism/fixtures/seattlerb/block_decomp_arg_splat_arg.txt b/test/prism/fixtures/seattlerb/block_decomp_arg_splat_arg.txt
new file mode 100644
index 0000000000..e64f4e8c3d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_decomp_arg_splat_arg.txt
@@ -0,0 +1 @@
+f { |(a, *b, c)| }
diff --git a/test/prism/fixtures/seattlerb/block_decomp_splat.txt b/test/prism/fixtures/seattlerb/block_decomp_splat.txt
new file mode 100644
index 0000000000..970f00a626
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_decomp_splat.txt
@@ -0,0 +1 @@
+f { |(*a)| }
diff --git a/test/prism/fixtures/seattlerb/block_kw.txt b/test/prism/fixtures/seattlerb/block_kw.txt
new file mode 100644
index 0000000000..bacfd32e80
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_kw.txt
@@ -0,0 +1 @@
+blah { |k:42| }
diff --git a/test/prism/fixtures/seattlerb/block_kw__required.txt b/test/prism/fixtures/seattlerb/block_kw__required.txt
new file mode 100644
index 0000000000..b84ab97037
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_kw__required.txt
@@ -0,0 +1 @@
+blah do |k:| end
diff --git a/test/prism/fixtures/seattlerb/block_kwarg_lvar.txt b/test/prism/fixtures/seattlerb/block_kwarg_lvar.txt
new file mode 100644
index 0000000000..390b9195e0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_kwarg_lvar.txt
@@ -0,0 +1 @@
+bl { |kw: :val| kw }
diff --git a/test/prism/fixtures/seattlerb/block_kwarg_lvar_multiple.txt b/test/prism/fixtures/seattlerb/block_kwarg_lvar_multiple.txt
new file mode 100644
index 0000000000..df3e4afde8
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_kwarg_lvar_multiple.txt
@@ -0,0 +1 @@
+bl { |kw: :val, kw2: :val2 | kw }
diff --git a/test/prism/fixtures/seattlerb/block_opt_arg.txt b/test/prism/fixtures/seattlerb/block_opt_arg.txt
new file mode 100644
index 0000000000..5e312fdf41
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_opt_arg.txt
@@ -0,0 +1 @@
+a { |b=1, c| }
diff --git a/test/prism/fixtures/seattlerb/block_opt_splat.txt b/test/prism/fixtures/seattlerb/block_opt_splat.txt
new file mode 100644
index 0000000000..772a3fc412
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_opt_splat.txt
@@ -0,0 +1 @@
+a { |b = 1, *c| }
diff --git a/test/prism/fixtures/seattlerb/block_opt_splat_arg_block_omfg.txt b/test/prism/fixtures/seattlerb/block_opt_splat_arg_block_omfg.txt
new file mode 100644
index 0000000000..76466f9d54
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_opt_splat_arg_block_omfg.txt
@@ -0,0 +1 @@
+a { |b=1, *c, d, &e| }
diff --git a/test/prism/fixtures/seattlerb/block_optarg.txt b/test/prism/fixtures/seattlerb/block_optarg.txt
new file mode 100644
index 0000000000..a471554da1
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_optarg.txt
@@ -0,0 +1 @@
+a { |b = :c| }
diff --git a/test/prism/fixtures/seattlerb/block_paren_splat.txt b/test/prism/fixtures/seattlerb/block_paren_splat.txt
new file mode 100644
index 0000000000..3dd4bba1ed
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_paren_splat.txt
@@ -0,0 +1 @@
+a { |(b, *c)| }
diff --git a/test/prism/fixtures/seattlerb/block_reg_optarg.txt b/test/prism/fixtures/seattlerb/block_reg_optarg.txt
new file mode 100644
index 0000000000..c024651f78
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_reg_optarg.txt
@@ -0,0 +1 @@
+a { |b, c = :d| }
diff --git a/test/prism/fixtures/seattlerb/block_return.txt b/test/prism/fixtures/seattlerb/block_return.txt
new file mode 100644
index 0000000000..f30ba71d8f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_return.txt
@@ -0,0 +1 @@
+return foo arg do |bar| end
diff --git a/test/prism/fixtures/seattlerb/block_scope.txt b/test/prism/fixtures/seattlerb/block_scope.txt
new file mode 100644
index 0000000000..7a83d8ab87
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_scope.txt
@@ -0,0 +1 @@
+a { |;b| }
diff --git a/test/prism/fixtures/seattlerb/block_splat_reg.txt b/test/prism/fixtures/seattlerb/block_splat_reg.txt
new file mode 100644
index 0000000000..58f0619e5d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/block_splat_reg.txt
@@ -0,0 +1 @@
+a { |*b, c| }
diff --git a/test/prism/fixtures/seattlerb/bug169.txt b/test/prism/fixtures/seattlerb/bug169.txt
new file mode 100644
index 0000000000..db2e5ace5e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug169.txt
@@ -0,0 +1 @@
+m () {}
diff --git a/test/prism/fixtures/seattlerb/bug179.txt b/test/prism/fixtures/seattlerb/bug179.txt
new file mode 100644
index 0000000000..02ae07a3be
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug179.txt
@@ -0,0 +1 @@
+p ()..nil
diff --git a/test/prism/fixtures/seattlerb/bug190.txt b/test/prism/fixtures/seattlerb/bug190.txt
new file mode 100644
index 0000000000..861b2d305f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug190.txt
@@ -0,0 +1 @@
+%r'\''
diff --git a/test/prism/fixtures/seattlerb/bug191.txt b/test/prism/fixtures/seattlerb/bug191.txt
new file mode 100644
index 0000000000..03f7fd1228
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug191.txt
@@ -0,0 +1,3 @@
+a ? "": b
+
+a ? '': b
diff --git a/test/prism/fixtures/seattlerb/bug202.txt b/test/prism/fixtures/seattlerb/bug202.txt
new file mode 100644
index 0000000000..a3b06ffdfc
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug202.txt
@@ -0,0 +1,2 @@
+$测试 = 1
+测试 = 1
diff --git a/test/prism/fixtures/seattlerb/bug236.txt b/test/prism/fixtures/seattlerb/bug236.txt
new file mode 100644
index 0000000000..cefe1eb058
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug236.txt
@@ -0,0 +1,3 @@
+x{|a,|}
+
+x{|a|}
diff --git a/test/prism/fixtures/seattlerb/bug290.txt b/test/prism/fixtures/seattlerb/bug290.txt
new file mode 100644
index 0000000000..dbcd28cd48
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug290.txt
@@ -0,0 +1,3 @@
+begin
+ foo
+end
diff --git a/test/prism/fixtures/seattlerb/bug_187.txt b/test/prism/fixtures/seattlerb/bug_187.txt
new file mode 100644
index 0000000000..1e1ecd8202
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_187.txt
@@ -0,0 +1,3 @@
+private def f
+a.b do end
+end
diff --git a/test/prism/fixtures/seattlerb/bug_215.txt b/test/prism/fixtures/seattlerb/bug_215.txt
new file mode 100644
index 0000000000..f0d09ba5ff
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_215.txt
@@ -0,0 +1 @@
+undef %s(foo)
diff --git a/test/prism/fixtures/seattlerb/bug_249.txt b/test/prism/fixtures/seattlerb/bug_249.txt
new file mode 100644
index 0000000000..ccccdf5326
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_249.txt
@@ -0,0 +1,4 @@
+mount (Class.new do
+def initialize
+end
+ end).new, :at => 'endpoint'
diff --git a/test/prism/fixtures/seattlerb/bug_and.txt b/test/prism/fixtures/seattlerb/bug_and.txt
new file mode 100644
index 0000000000..6243359a9e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_and.txt
@@ -0,0 +1,4 @@
+true and
+true
+
+true and []
diff --git a/test/prism/fixtures/seattlerb/bug_args__19.txt b/test/prism/fixtures/seattlerb/bug_args__19.txt
new file mode 100644
index 0000000000..08466554fd
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_args__19.txt
@@ -0,0 +1 @@
+f { |(a, b)| d }
diff --git a/test/prism/fixtures/seattlerb/bug_args_masgn.txt b/test/prism/fixtures/seattlerb/bug_args_masgn.txt
new file mode 100644
index 0000000000..e0a71e9197
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_args_masgn.txt
@@ -0,0 +1 @@
+f { |(a, b), c| }
diff --git a/test/prism/fixtures/seattlerb/bug_args_masgn2.txt b/test/prism/fixtures/seattlerb/bug_args_masgn2.txt
new file mode 100644
index 0000000000..2f12756bfe
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_args_masgn2.txt
@@ -0,0 +1 @@
+f { |((a, b), c), d| }
diff --git a/test/prism/fixtures/seattlerb/bug_args_masgn_outer_parens__19.txt b/test/prism/fixtures/seattlerb/bug_args_masgn_outer_parens__19.txt
new file mode 100644
index 0000000000..a2b0178676
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_args_masgn_outer_parens__19.txt
@@ -0,0 +1 @@
+f { |((k, v), i)| }
diff --git a/test/prism/fixtures/seattlerb/bug_call_arglist_parens.txt b/test/prism/fixtures/seattlerb/bug_call_arglist_parens.txt
new file mode 100644
index 0000000000..4f04368802
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_call_arglist_parens.txt
@@ -0,0 +1,11 @@
+ def f
+ g ( 1), 2
+ end
+
+
+ def f()
+ g (1), 2
+ end
+
+
+g ( 1), 2
diff --git a/test/prism/fixtures/seattlerb/bug_case_when_regexp.txt b/test/prism/fixtures/seattlerb/bug_case_when_regexp.txt
new file mode 100644
index 0000000000..2536696a42
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_case_when_regexp.txt
@@ -0,0 +1 @@
+case :x; when /x/ then end
diff --git a/test/prism/fixtures/seattlerb/bug_comma.txt b/test/prism/fixtures/seattlerb/bug_comma.txt
new file mode 100644
index 0000000000..d86f1ea9dd
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_comma.txt
@@ -0,0 +1 @@
+if test ?d, dir then end
diff --git a/test/prism/fixtures/seattlerb/bug_cond_pct.txt b/test/prism/fixtures/seattlerb/bug_cond_pct.txt
new file mode 100644
index 0000000000..1b4f90058e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_cond_pct.txt
@@ -0,0 +1 @@
+case; when %r%blahblah%; end
diff --git a/test/prism/fixtures/seattlerb/bug_hash_args.txt b/test/prism/fixtures/seattlerb/bug_hash_args.txt
new file mode 100644
index 0000000000..b815f8a666
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_hash_args.txt
@@ -0,0 +1 @@
+foo(:bar, baz: nil)
diff --git a/test/prism/fixtures/seattlerb/bug_hash_args_trailing_comma.txt b/test/prism/fixtures/seattlerb/bug_hash_args_trailing_comma.txt
new file mode 100644
index 0000000000..6057b245a5
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_hash_args_trailing_comma.txt
@@ -0,0 +1 @@
+foo(:bar, baz: nil,)
diff --git a/test/prism/fixtures/seattlerb/bug_hash_interp_array.txt b/test/prism/fixtures/seattlerb/bug_hash_interp_array.txt
new file mode 100644
index 0000000000..01fe238056
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_hash_interp_array.txt
@@ -0,0 +1 @@
+{ "#{}": [] }
diff --git a/test/prism/fixtures/seattlerb/bug_masgn_right.txt b/test/prism/fixtures/seattlerb/bug_masgn_right.txt
new file mode 100644
index 0000000000..12ea7b8d62
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_masgn_right.txt
@@ -0,0 +1 @@
+f { |a, (b, c)| }
diff --git a/test/prism/fixtures/seattlerb/bug_not_parens.txt b/test/prism/fixtures/seattlerb/bug_not_parens.txt
new file mode 100644
index 0000000000..8847b7bec6
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_not_parens.txt
@@ -0,0 +1 @@
+not(a)
diff --git a/test/prism/fixtures/seattlerb/bug_op_asgn_rescue.txt b/test/prism/fixtures/seattlerb/bug_op_asgn_rescue.txt
new file mode 100644
index 0000000000..6a0b25cbdc
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/bug_op_asgn_rescue.txt
@@ -0,0 +1 @@
+a ||= b rescue nil
diff --git a/test/prism/fixtures/seattlerb/call_and.txt b/test/prism/fixtures/seattlerb/call_and.txt
new file mode 100644
index 0000000000..c17be8f356
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_and.txt
@@ -0,0 +1 @@
+1 & 2
diff --git a/test/prism/fixtures/seattlerb/call_arg_assoc.txt b/test/prism/fixtures/seattlerb/call_arg_assoc.txt
new file mode 100644
index 0000000000..376c299be5
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_arg_assoc.txt
@@ -0,0 +1 @@
+f(1, 2=>3)
diff --git a/test/prism/fixtures/seattlerb/call_arg_assoc_kwsplat.txt b/test/prism/fixtures/seattlerb/call_arg_assoc_kwsplat.txt
new file mode 100644
index 0000000000..a4be0fb62c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_arg_assoc_kwsplat.txt
@@ -0,0 +1 @@
+f(1, kw: 2, **3)
diff --git a/test/prism/fixtures/seattlerb/call_arg_kwsplat.txt b/test/prism/fixtures/seattlerb/call_arg_kwsplat.txt
new file mode 100644
index 0000000000..4848fd9e8d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_arg_kwsplat.txt
@@ -0,0 +1 @@
+a(b, **1)
diff --git a/test/prism/fixtures/seattlerb/call_args_assoc_quoted.txt b/test/prism/fixtures/seattlerb/call_args_assoc_quoted.txt
new file mode 100644
index 0000000000..0af2259577
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_args_assoc_quoted.txt
@@ -0,0 +1,5 @@
+x "#{k}":42
+
+x "k":42
+
+x 'k':42
diff --git a/test/prism/fixtures/seattlerb/call_args_assoc_trailing_comma.txt b/test/prism/fixtures/seattlerb/call_args_assoc_trailing_comma.txt
new file mode 100644
index 0000000000..6ad08f3238
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_args_assoc_trailing_comma.txt
@@ -0,0 +1 @@
+f(1, 2=>3,)
diff --git a/test/prism/fixtures/seattlerb/call_args_command.txt b/test/prism/fixtures/seattlerb/call_args_command.txt
new file mode 100644
index 0000000000..dd6df29c7b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_args_command.txt
@@ -0,0 +1 @@
+a.b c.d 1
diff --git a/test/prism/fixtures/seattlerb/call_array_arg.txt b/test/prism/fixtures/seattlerb/call_array_arg.txt
new file mode 100644
index 0000000000..5c724fa328
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_array_arg.txt
@@ -0,0 +1 @@
+1 == [:b, :c]
diff --git a/test/prism/fixtures/seattlerb/call_array_block_call.txt b/test/prism/fixtures/seattlerb/call_array_block_call.txt
new file mode 100644
index 0000000000..6d4c1b276e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_array_block_call.txt
@@ -0,0 +1 @@
+a [ nil, b do end ]
diff --git a/test/prism/fixtures/seattlerb/call_array_lambda_block_call.txt b/test/prism/fixtures/seattlerb/call_array_lambda_block_call.txt
new file mode 100644
index 0000000000..dc5b5807b2
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_array_lambda_block_call.txt
@@ -0,0 +1,2 @@
+a [->() {}] do
+end
diff --git a/test/prism/fixtures/seattlerb/call_array_lit_inline_hash.txt b/test/prism/fixtures/seattlerb/call_array_lit_inline_hash.txt
new file mode 100644
index 0000000000..daba00947e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_array_lit_inline_hash.txt
@@ -0,0 +1 @@
+a([:b, :c => 1])
diff --git a/test/prism/fixtures/seattlerb/call_assoc.txt b/test/prism/fixtures/seattlerb/call_assoc.txt
new file mode 100644
index 0000000000..2adc1eee1c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_assoc.txt
@@ -0,0 +1 @@
+f(2=>3)
diff --git a/test/prism/fixtures/seattlerb/call_assoc_new.txt b/test/prism/fixtures/seattlerb/call_assoc_new.txt
new file mode 100644
index 0000000000..b8457bfdfc
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_assoc_new.txt
@@ -0,0 +1 @@
+f(a:3)
diff --git a/test/prism/fixtures/seattlerb/call_assoc_new_if_multiline.txt b/test/prism/fixtures/seattlerb/call_assoc_new_if_multiline.txt
new file mode 100644
index 0000000000..fe0a37dabb
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_assoc_new_if_multiline.txt
@@ -0,0 +1,5 @@
+a(b: if :c
+1
+else
+2
+end)
diff --git a/test/prism/fixtures/seattlerb/call_assoc_trailing_comma.txt b/test/prism/fixtures/seattlerb/call_assoc_trailing_comma.txt
new file mode 100644
index 0000000000..4d86a4541d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_assoc_trailing_comma.txt
@@ -0,0 +1 @@
+f(1=>2,)
diff --git a/test/prism/fixtures/seattlerb/call_bang_command_call.txt b/test/prism/fixtures/seattlerb/call_bang_command_call.txt
new file mode 100644
index 0000000000..4f3ba4b93c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_bang_command_call.txt
@@ -0,0 +1 @@
+! a.b 1
diff --git a/test/prism/fixtures/seattlerb/call_bang_squiggle.txt b/test/prism/fixtures/seattlerb/call_bang_squiggle.txt
new file mode 100644
index 0000000000..d7039f910a
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_bang_squiggle.txt
@@ -0,0 +1 @@
+1 !~ 2
diff --git a/test/prism/fixtures/seattlerb/call_begin_call_block_call.txt b/test/prism/fixtures/seattlerb/call_begin_call_block_call.txt
new file mode 100644
index 0000000000..e9b43491fe
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_begin_call_block_call.txt
@@ -0,0 +1,3 @@
+a begin
+b.c do end
+end
diff --git a/test/prism/fixtures/seattlerb/call_block_arg_named.txt b/test/prism/fixtures/seattlerb/call_block_arg_named.txt
new file mode 100644
index 0000000000..08fea89d11
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_block_arg_named.txt
@@ -0,0 +1 @@
+x(&blk)
diff --git a/test/prism/fixtures/seattlerb/call_carat.txt b/test/prism/fixtures/seattlerb/call_carat.txt
new file mode 100644
index 0000000000..3e88c09837
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_carat.txt
@@ -0,0 +1 @@
+1 ^ 2
diff --git a/test/prism/fixtures/seattlerb/call_colon2.txt b/test/prism/fixtures/seattlerb/call_colon2.txt
new file mode 100644
index 0000000000..47aab7e637
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_colon2.txt
@@ -0,0 +1 @@
+A::b
diff --git a/test/prism/fixtures/seattlerb/call_colon_parens.txt b/test/prism/fixtures/seattlerb/call_colon_parens.txt
new file mode 100644
index 0000000000..51ed4df11b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_colon_parens.txt
@@ -0,0 +1 @@
+1::()
diff --git a/test/prism/fixtures/seattlerb/call_div.txt b/test/prism/fixtures/seattlerb/call_div.txt
new file mode 100644
index 0000000000..85b4d7b0b0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_div.txt
@@ -0,0 +1 @@
+1 / 2
diff --git a/test/prism/fixtures/seattlerb/call_dot_parens.txt b/test/prism/fixtures/seattlerb/call_dot_parens.txt
new file mode 100644
index 0000000000..0270596a07
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_dot_parens.txt
@@ -0,0 +1 @@
+1.()
diff --git a/test/prism/fixtures/seattlerb/call_env.txt b/test/prism/fixtures/seattlerb/call_env.txt
new file mode 100644
index 0000000000..dadc0d3861
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_env.txt
@@ -0,0 +1 @@
+a.happy
diff --git a/test/prism/fixtures/seattlerb/call_eq3.txt b/test/prism/fixtures/seattlerb/call_eq3.txt
new file mode 100644
index 0000000000..6a2fb465cb
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_eq3.txt
@@ -0,0 +1 @@
+1 === 2
diff --git a/test/prism/fixtures/seattlerb/call_gt.txt b/test/prism/fixtures/seattlerb/call_gt.txt
new file mode 100644
index 0000000000..9d0a1caa90
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_gt.txt
@@ -0,0 +1 @@
+1 > 2
diff --git a/test/prism/fixtures/seattlerb/call_kwsplat.txt b/test/prism/fixtures/seattlerb/call_kwsplat.txt
new file mode 100644
index 0000000000..eda700c3e1
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_kwsplat.txt
@@ -0,0 +1 @@
+a(**1)
diff --git a/test/prism/fixtures/seattlerb/call_leading_dots.txt b/test/prism/fixtures/seattlerb/call_leading_dots.txt
new file mode 100644
index 0000000000..1e7b2e5179
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_leading_dots.txt
@@ -0,0 +1,3 @@
+a
+.b
+.c
diff --git a/test/prism/fixtures/seattlerb/call_leading_dots_comment.txt b/test/prism/fixtures/seattlerb/call_leading_dots_comment.txt
new file mode 100644
index 0000000000..c5deec5642
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_leading_dots_comment.txt
@@ -0,0 +1,4 @@
+a
+.b
+#.c
+.d
diff --git a/test/prism/fixtures/seattlerb/call_lt.txt b/test/prism/fixtures/seattlerb/call_lt.txt
new file mode 100644
index 0000000000..17e69c79b5
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_lt.txt
@@ -0,0 +1 @@
+1 < 2
diff --git a/test/prism/fixtures/seattlerb/call_lte.txt b/test/prism/fixtures/seattlerb/call_lte.txt
new file mode 100644
index 0000000000..7574027634
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_lte.txt
@@ -0,0 +1 @@
+1 <= 2
diff --git a/test/prism/fixtures/seattlerb/call_not.txt b/test/prism/fixtures/seattlerb/call_not.txt
new file mode 100644
index 0000000000..51e4742f55
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_not.txt
@@ -0,0 +1 @@
+not 42
diff --git a/test/prism/fixtures/seattlerb/call_pipe.txt b/test/prism/fixtures/seattlerb/call_pipe.txt
new file mode 100644
index 0000000000..1555910665
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_pipe.txt
@@ -0,0 +1 @@
+1 | 2
diff --git a/test/prism/fixtures/seattlerb/call_rshift.txt b/test/prism/fixtures/seattlerb/call_rshift.txt
new file mode 100644
index 0000000000..9ff1def4e0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_rshift.txt
@@ -0,0 +1 @@
+1 >> 2
diff --git a/test/prism/fixtures/seattlerb/call_self_brackets.txt b/test/prism/fixtures/seattlerb/call_self_brackets.txt
new file mode 100644
index 0000000000..6533df2ce0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_self_brackets.txt
@@ -0,0 +1 @@
+self[1]
diff --git a/test/prism/fixtures/seattlerb/call_spaceship.txt b/test/prism/fixtures/seattlerb/call_spaceship.txt
new file mode 100644
index 0000000000..905c3a1c46
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_spaceship.txt
@@ -0,0 +1 @@
+1 <=> 2
diff --git a/test/prism/fixtures/seattlerb/call_stabby_do_end_with_block.txt b/test/prism/fixtures/seattlerb/call_stabby_do_end_with_block.txt
new file mode 100644
index 0000000000..2d1afdad28
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_stabby_do_end_with_block.txt
@@ -0,0 +1 @@
+a -> do 1 end do 2 end
diff --git a/test/prism/fixtures/seattlerb/call_stabby_with_braces_block.txt b/test/prism/fixtures/seattlerb/call_stabby_with_braces_block.txt
new file mode 100644
index 0000000000..0d995a04d1
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_stabby_with_braces_block.txt
@@ -0,0 +1 @@
+a -> { 1 } do 2 end
diff --git a/test/prism/fixtures/seattlerb/call_star.txt b/test/prism/fixtures/seattlerb/call_star.txt
new file mode 100644
index 0000000000..096ec022d4
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_star.txt
@@ -0,0 +1 @@
+1 * 2
diff --git a/test/prism/fixtures/seattlerb/call_star2.txt b/test/prism/fixtures/seattlerb/call_star2.txt
new file mode 100644
index 0000000000..bef4719d3c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_star2.txt
@@ -0,0 +1 @@
+1 ** 2
diff --git a/test/prism/fixtures/seattlerb/call_trailing_comma.txt b/test/prism/fixtures/seattlerb/call_trailing_comma.txt
new file mode 100644
index 0000000000..e9a3ca35be
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_trailing_comma.txt
@@ -0,0 +1 @@
+f(1,)
diff --git a/test/prism/fixtures/seattlerb/call_trailing_dots.txt b/test/prism/fixtures/seattlerb/call_trailing_dots.txt
new file mode 100644
index 0000000000..960cdbb45f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_trailing_dots.txt
@@ -0,0 +1,3 @@
+a.
+b.
+c
diff --git a/test/prism/fixtures/seattlerb/call_unary_bang.txt b/test/prism/fixtures/seattlerb/call_unary_bang.txt
new file mode 100644
index 0000000000..91f702d4a9
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/call_unary_bang.txt
@@ -0,0 +1 @@
+!1
diff --git a/test/prism/fixtures/seattlerb/case_in.txt b/test/prism/fixtures/seattlerb/case_in.txt
new file mode 100644
index 0000000000..0835da0956
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in.txt
@@ -0,0 +1,111 @@
+case :a
+in "b":
+end
+
+case :a
+in %I[a b]
+end
+
+case :a
+in %W[a b]
+end
+
+case :a
+in %i[a b]
+end
+
+case :a
+in %w[a b]
+end
+
+case :a
+in (...10)
+end
+
+case :a
+in (..10)
+end
+
+case :a
+in (1...)
+end
+
+case :a
+in (1...3)
+end
+
+case :a
+in (42)
+end
+
+case :a
+in **nil
+end
+
+case :a
+in /regexp/
+end
+
+case :a
+in :b, *_, :c
+end
+
+case :a
+in :b, [:c]
+end
+
+case :a
+in Symbol()
+end
+
+case :a
+in Symbol(*lhs, x, *rhs)
+end
+
+case :a
+in Symbol[*lhs, x, *rhs]
+end
+
+case :a
+in [->(b) { true }, c]
+end
+
+case :a
+in [:a, b, c, [:d, *e, nil]]
+end
+
+case :a
+in [A, *, B]
+end
+
+case :a
+in [[:b, c], [:d, ^e]]
+end
+
+case :a
+in []
+end
+
+case :a
+in [^(a)]
+end
+
+case :a
+in [^@a, ^$b, ^@@c]
+end
+
+case :a
+in `echo hi`
+end
+
+case :a
+in nil, nil, nil
+end
+
+case :a
+in { "b": }
+end
+
+case :a
+in {}
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_31.txt b/test/prism/fixtures/seattlerb/case_in_31.txt
new file mode 100644
index 0000000000..b9bf25b132
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_31.txt
@@ -0,0 +1,4 @@
+case :a
+in [:b, *c]
+ :d
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_37.txt b/test/prism/fixtures/seattlerb/case_in_37.txt
new file mode 100644
index 0000000000..25b6fb9261
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_37.txt
@@ -0,0 +1,4 @@
+case :a
+in { b: [Hash, *] }
+ :c
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_42.txt b/test/prism/fixtures/seattlerb/case_in_42.txt
new file mode 100644
index 0000000000..bc6a2233f5
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_42.txt
@@ -0,0 +1,3 @@
+case :a
+in :b, *_ then nil
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_42_2.txt b/test/prism/fixtures/seattlerb/case_in_42_2.txt
new file mode 100644
index 0000000000..ce4b65a5d0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_42_2.txt
@@ -0,0 +1,3 @@
+case :a
+in A(*list) then nil
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_47.txt b/test/prism/fixtures/seattlerb/case_in_47.txt
new file mode 100644
index 0000000000..60f17ed7ce
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_47.txt
@@ -0,0 +1,4 @@
+case :a
+in [*, :b, :c]
+ :d
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_67.txt b/test/prism/fixtures/seattlerb/case_in_67.txt
new file mode 100644
index 0000000000..c1c55e68c7
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_67.txt
@@ -0,0 +1,3 @@
+case :a
+in 1.. then nil
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_86.txt b/test/prism/fixtures/seattlerb/case_in_86.txt
new file mode 100644
index 0000000000..63ba92e533
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_86.txt
@@ -0,0 +1,3 @@
+case [:a, :b]
+in ::NilClass, * then nil
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_86_2.txt b/test/prism/fixtures/seattlerb/case_in_86_2.txt
new file mode 100644
index 0000000000..4ad16c451a
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_86_2.txt
@@ -0,0 +1,3 @@
+case [:a, :b]
+in *, ::NilClass then nil
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_array_pat_const.txt b/test/prism/fixtures/seattlerb/case_in_array_pat_const.txt
new file mode 100644
index 0000000000..8551e48e2c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_array_pat_const.txt
@@ -0,0 +1,4 @@
+case :a
+in B[c]
+ :d
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_array_pat_const2.txt b/test/prism/fixtures/seattlerb/case_in_array_pat_const2.txt
new file mode 100644
index 0000000000..fca423ea61
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_array_pat_const2.txt
@@ -0,0 +1,4 @@
+case :a
+in B::C[d]
+ :e
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_array_pat_paren_assign.txt b/test/prism/fixtures/seattlerb/case_in_array_pat_paren_assign.txt
new file mode 100644
index 0000000000..c56f728337
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_array_pat_paren_assign.txt
@@ -0,0 +1,4 @@
+case :a
+in B(C => d)
+ :d
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_const.txt b/test/prism/fixtures/seattlerb/case_in_const.txt
new file mode 100644
index 0000000000..5b0dcc18e2
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_const.txt
@@ -0,0 +1,4 @@
+case Array
+in Class
+ :b
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_else.txt b/test/prism/fixtures/seattlerb/case_in_else.txt
new file mode 100644
index 0000000000..6f096862c5
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_else.txt
@@ -0,0 +1,7 @@
+case Array
+in Class
+ :b
+else
+ :c
+end
+
diff --git a/test/prism/fixtures/seattlerb/case_in_find.txt b/test/prism/fixtures/seattlerb/case_in_find.txt
new file mode 100644
index 0000000000..476fcabe11
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_find.txt
@@ -0,0 +1,3 @@
+case :a
+ in *a, :+, *b
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_find_array.txt b/test/prism/fixtures/seattlerb/case_in_find_array.txt
new file mode 100644
index 0000000000..5eb4010b7f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_find_array.txt
@@ -0,0 +1,3 @@
+case :a
+in [*, :b, c, *]
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_hash_pat.txt b/test/prism/fixtures/seattlerb/case_in_hash_pat.txt
new file mode 100644
index 0000000000..cb012e8d99
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_hash_pat.txt
@@ -0,0 +1,5 @@
+case :a
+in { b: 'c', d: "e" } then
+ :f
+end
+
diff --git a/test/prism/fixtures/seattlerb/case_in_hash_pat_assign.txt b/test/prism/fixtures/seattlerb/case_in_hash_pat_assign.txt
new file mode 100644
index 0000000000..58fd59ff9c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_hash_pat_assign.txt
@@ -0,0 +1,4 @@
+case :a
+in { b: Integer => x, d: "e", f: } then
+ :g
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_hash_pat_paren_assign.txt b/test/prism/fixtures/seattlerb/case_in_hash_pat_paren_assign.txt
new file mode 100644
index 0000000000..de3a10740c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_hash_pat_paren_assign.txt
@@ -0,0 +1,4 @@
+case :a
+in B(a: 42)
+ :d
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_hash_pat_paren_true.txt b/test/prism/fixtures/seattlerb/case_in_hash_pat_paren_true.txt
new file mode 100644
index 0000000000..449fd0d4d4
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_hash_pat_paren_true.txt
@@ -0,0 +1,5 @@
+case :a
+in b: true then
+ :c
+end
+
diff --git a/test/prism/fixtures/seattlerb/case_in_hash_pat_rest.txt b/test/prism/fixtures/seattlerb/case_in_hash_pat_rest.txt
new file mode 100644
index 0000000000..6f67cb1d10
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_hash_pat_rest.txt
@@ -0,0 +1,3 @@
+case :a
+in b: c, **rest then :d
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_hash_pat_rest_solo.txt b/test/prism/fixtures/seattlerb/case_in_hash_pat_rest_solo.txt
new file mode 100644
index 0000000000..91d0592412
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_hash_pat_rest_solo.txt
@@ -0,0 +1,3 @@
+case :a
+in **rest then :d
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_if_unless_post_mod.txt b/test/prism/fixtures/seattlerb/case_in_if_unless_post_mod.txt
new file mode 100644
index 0000000000..dbe24a5c8a
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_if_unless_post_mod.txt
@@ -0,0 +1,6 @@
+case :a
+in A if true
+ :C
+in D unless false
+ :E
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_multiple.txt b/test/prism/fixtures/seattlerb/case_in_multiple.txt
new file mode 100644
index 0000000000..1b6dd06cfe
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_multiple.txt
@@ -0,0 +1,6 @@
+case :a
+in A::B
+ :C
+in D::E
+ :F
+end
diff --git a/test/prism/fixtures/seattlerb/case_in_or.txt b/test/prism/fixtures/seattlerb/case_in_or.txt
new file mode 100644
index 0000000000..875e37749f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/case_in_or.txt
@@ -0,0 +1,5 @@
+case :a
+in B | C
+ :d
+end
+
diff --git a/test/prism/fixtures/seattlerb/class_comments.txt b/test/prism/fixtures/seattlerb/class_comments.txt
new file mode 100644
index 0000000000..9701eca7e5
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/class_comments.txt
@@ -0,0 +1,9 @@
+# blah 1
+# blah 2
+
+class X
+ # blah 3
+ def blah
+ # blah 4
+ end
+end
diff --git a/test/prism/fixtures/seattlerb/cond_unary_minus.txt b/test/prism/fixtures/seattlerb/cond_unary_minus.txt
new file mode 100644
index 0000000000..80293115da
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/cond_unary_minus.txt
@@ -0,0 +1 @@
+if -1; end
diff --git a/test/prism/fixtures/seattlerb/const_2_op_asgn_or2.txt b/test/prism/fixtures/seattlerb/const_2_op_asgn_or2.txt
new file mode 100644
index 0000000000..6912c2d76b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/const_2_op_asgn_or2.txt
@@ -0,0 +1 @@
+::X::Y ||= 1
diff --git a/test/prism/fixtures/seattlerb/const_3_op_asgn_or.txt b/test/prism/fixtures/seattlerb/const_3_op_asgn_or.txt
new file mode 100644
index 0000000000..bbcd25a369
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/const_3_op_asgn_or.txt
@@ -0,0 +1 @@
+::X ||= 1
diff --git a/test/prism/fixtures/seattlerb/const_op_asgn_and1.txt b/test/prism/fixtures/seattlerb/const_op_asgn_and1.txt
new file mode 100644
index 0000000000..3964df0ead
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/const_op_asgn_and1.txt
@@ -0,0 +1 @@
+::X &= 1
diff --git a/test/prism/fixtures/seattlerb/const_op_asgn_and2.txt b/test/prism/fixtures/seattlerb/const_op_asgn_and2.txt
new file mode 100644
index 0000000000..1bef4b4154
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/const_op_asgn_and2.txt
@@ -0,0 +1 @@
+::X &&= 1
diff --git a/test/prism/fixtures/seattlerb/const_op_asgn_or.txt b/test/prism/fixtures/seattlerb/const_op_asgn_or.txt
new file mode 100644
index 0000000000..729e425262
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/const_op_asgn_or.txt
@@ -0,0 +1 @@
+X::Y ||= 1
diff --git a/test/prism/fixtures/seattlerb/defined_eh_parens.txt b/test/prism/fixtures/seattlerb/defined_eh_parens.txt
new file mode 100644
index 0000000000..5ca5d9f4c4
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defined_eh_parens.txt
@@ -0,0 +1 @@
+defined?(42)
diff --git a/test/prism/fixtures/seattlerb/defn_arg_asplat_arg.txt b/test/prism/fixtures/seattlerb/defn_arg_asplat_arg.txt
new file mode 100644
index 0000000000..f629a5de60
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_arg_asplat_arg.txt
@@ -0,0 +1 @@
+def call(interp, *, args) end
diff --git a/test/prism/fixtures/seattlerb/defn_arg_forward_args.txt b/test/prism/fixtures/seattlerb/defn_arg_forward_args.txt
new file mode 100644
index 0000000000..500e2e1fe0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_arg_forward_args.txt
@@ -0,0 +1 @@
+def a(x, ...); b(x, ...); end
diff --git a/test/prism/fixtures/seattlerb/defn_args_forward_args.txt b/test/prism/fixtures/seattlerb/defn_args_forward_args.txt
new file mode 100644
index 0000000000..fc1ee138de
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_args_forward_args.txt
@@ -0,0 +1 @@
+def a(x, y, z, ...); b(:get, z, ...); end
diff --git a/test/prism/fixtures/seattlerb/defn_comments.txt b/test/prism/fixtures/seattlerb/defn_comments.txt
new file mode 100644
index 0000000000..04c7ea1a10
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_comments.txt
@@ -0,0 +1,5 @@
+# blah 1
+# blah 2
+
+def blah
+end
diff --git a/test/prism/fixtures/seattlerb/defn_endless_command.txt b/test/prism/fixtures/seattlerb/defn_endless_command.txt
new file mode 100644
index 0000000000..172de2ca6c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_endless_command.txt
@@ -0,0 +1 @@
+def some_method = other_method 42
diff --git a/test/prism/fixtures/seattlerb/defn_endless_command_rescue.txt b/test/prism/fixtures/seattlerb/defn_endless_command_rescue.txt
new file mode 100644
index 0000000000..05ed392e38
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_endless_command_rescue.txt
@@ -0,0 +1 @@
+def some_method = other_method 42 rescue 24
diff --git a/test/prism/fixtures/seattlerb/defn_forward_args.txt b/test/prism/fixtures/seattlerb/defn_forward_args.txt
new file mode 100644
index 0000000000..46ed199875
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_forward_args.txt
@@ -0,0 +1 @@
+def a(...); b(...); end
diff --git a/test/prism/fixtures/seattlerb/defn_forward_args__no_parens.txt b/test/prism/fixtures/seattlerb/defn_forward_args__no_parens.txt
new file mode 100644
index 0000000000..2d34077c93
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_forward_args__no_parens.txt
@@ -0,0 +1,3 @@
+def f ...
+ m(...)
+end
diff --git a/test/prism/fixtures/seattlerb/defn_kwarg_env.txt b/test/prism/fixtures/seattlerb/defn_kwarg_env.txt
new file mode 100644
index 0000000000..b512677195
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_kwarg_env.txt
@@ -0,0 +1 @@
+def test(**testing) test_splat(**testing) end
diff --git a/test/prism/fixtures/seattlerb/defn_kwarg_kwarg.txt b/test/prism/fixtures/seattlerb/defn_kwarg_kwarg.txt
new file mode 100644
index 0000000000..3962d2645c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_kwarg_kwarg.txt
@@ -0,0 +1 @@
+def f(a, b: 1, c: 2) end
diff --git a/test/prism/fixtures/seattlerb/defn_kwarg_kwsplat.txt b/test/prism/fixtures/seattlerb/defn_kwarg_kwsplat.txt
new file mode 100644
index 0000000000..bd39819482
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_kwarg_kwsplat.txt
@@ -0,0 +1 @@
+def a(b: 1, **c) end
diff --git a/test/prism/fixtures/seattlerb/defn_kwarg_kwsplat_anon.txt b/test/prism/fixtures/seattlerb/defn_kwarg_kwsplat_anon.txt
new file mode 100644
index 0000000000..aba71cba07
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_kwarg_kwsplat_anon.txt
@@ -0,0 +1 @@
+def a(b: 1, **) end
diff --git a/test/prism/fixtures/seattlerb/defn_kwarg_lvar.txt b/test/prism/fixtures/seattlerb/defn_kwarg_lvar.txt
new file mode 100644
index 0000000000..9eac108cca
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_kwarg_lvar.txt
@@ -0,0 +1 @@
+def fun(kw: :val); kw; end
diff --git a/test/prism/fixtures/seattlerb/defn_kwarg_no_parens.txt b/test/prism/fixtures/seattlerb/defn_kwarg_no_parens.txt
new file mode 100644
index 0000000000..481457bf0e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_kwarg_no_parens.txt
@@ -0,0 +1,2 @@
+def f a: 1
+end
diff --git a/test/prism/fixtures/seattlerb/defn_kwarg_val.txt b/test/prism/fixtures/seattlerb/defn_kwarg_val.txt
new file mode 100644
index 0000000000..1a2803926f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_kwarg_val.txt
@@ -0,0 +1 @@
+def f(a, b:1) end
diff --git a/test/prism/fixtures/seattlerb/defn_no_kwargs.txt b/test/prism/fixtures/seattlerb/defn_no_kwargs.txt
new file mode 100644
index 0000000000..857ec8debb
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_no_kwargs.txt
@@ -0,0 +1 @@
+def x(**nil); end
diff --git a/test/prism/fixtures/seattlerb/defn_oneliner.txt b/test/prism/fixtures/seattlerb/defn_oneliner.txt
new file mode 100644
index 0000000000..4aef08ce46
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_oneliner.txt
@@ -0,0 +1 @@
+def exec(cmd) = system(cmd)
diff --git a/test/prism/fixtures/seattlerb/defn_oneliner_eq2.txt b/test/prism/fixtures/seattlerb/defn_oneliner_eq2.txt
new file mode 100644
index 0000000000..1b1ce27a15
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_oneliner_eq2.txt
@@ -0,0 +1,3 @@
+class X
+ def ==(o) = 42
+end
diff --git a/test/prism/fixtures/seattlerb/defn_oneliner_noargs.txt b/test/prism/fixtures/seattlerb/defn_oneliner_noargs.txt
new file mode 100644
index 0000000000..cb4f76d244
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_oneliner_noargs.txt
@@ -0,0 +1 @@
+def exec = system
diff --git a/test/prism/fixtures/seattlerb/defn_oneliner_noargs_parentheses.txt b/test/prism/fixtures/seattlerb/defn_oneliner_noargs_parentheses.txt
new file mode 100644
index 0000000000..c582e896c1
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_oneliner_noargs_parentheses.txt
@@ -0,0 +1 @@
+def exec() = system
diff --git a/test/prism/fixtures/seattlerb/defn_oneliner_rescue.txt b/test/prism/fixtures/seattlerb/defn_oneliner_rescue.txt
new file mode 100644
index 0000000000..ffe2228c9d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_oneliner_rescue.txt
@@ -0,0 +1,13 @@
+def exec(cmd)
+ system(cmd)
+rescue
+ nil
+end
+
+
+def exec(cmd)
+ system(cmd) rescue nil
+end
+
+
+def exec(cmd) = system(cmd) rescue nil
diff --git a/test/prism/fixtures/seattlerb/defn_opt_last_arg.txt b/test/prism/fixtures/seattlerb/defn_opt_last_arg.txt
new file mode 100644
index 0000000000..91500bf137
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_opt_last_arg.txt
@@ -0,0 +1,2 @@
+def m arg = false
+end
diff --git a/test/prism/fixtures/seattlerb/defn_opt_reg.txt b/test/prism/fixtures/seattlerb/defn_opt_reg.txt
new file mode 100644
index 0000000000..c665674bc4
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_opt_reg.txt
@@ -0,0 +1 @@
+def f(a=nil, b) end
diff --git a/test/prism/fixtures/seattlerb/defn_opt_splat_arg.txt b/test/prism/fixtures/seattlerb/defn_opt_splat_arg.txt
new file mode 100644
index 0000000000..876398b478
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_opt_splat_arg.txt
@@ -0,0 +1 @@
+def f (a = 1, *b, c) end
diff --git a/test/prism/fixtures/seattlerb/defn_powarg.txt b/test/prism/fixtures/seattlerb/defn_powarg.txt
new file mode 100644
index 0000000000..73415f0db9
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_powarg.txt
@@ -0,0 +1 @@
+def f(**opts) end
diff --git a/test/prism/fixtures/seattlerb/defn_reg_opt_reg.txt b/test/prism/fixtures/seattlerb/defn_reg_opt_reg.txt
new file mode 100644
index 0000000000..69f501a38e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_reg_opt_reg.txt
@@ -0,0 +1 @@
+def f(a, b = :c, d) end
diff --git a/test/prism/fixtures/seattlerb/defn_splat_arg.txt b/test/prism/fixtures/seattlerb/defn_splat_arg.txt
new file mode 100644
index 0000000000..a2a84bed30
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_splat_arg.txt
@@ -0,0 +1 @@
+def f(*, a) end
diff --git a/test/prism/fixtures/seattlerb/defn_unary_not.txt b/test/prism/fixtures/seattlerb/defn_unary_not.txt
new file mode 100644
index 0000000000..fb83c84a13
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defn_unary_not.txt
@@ -0,0 +1 @@
+def !@; true; end
diff --git a/test/prism/fixtures/seattlerb/defns_reserved.txt b/test/prism/fixtures/seattlerb/defns_reserved.txt
new file mode 100644
index 0000000000..7de9322f0d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defns_reserved.txt
@@ -0,0 +1 @@
+def self.return; end
diff --git a/test/prism/fixtures/seattlerb/defs_as_arg_with_do_block_inside.txt b/test/prism/fixtures/seattlerb/defs_as_arg_with_do_block_inside.txt
new file mode 100644
index 0000000000..4d493d73dd
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defs_as_arg_with_do_block_inside.txt
@@ -0,0 +1 @@
+p def self.b; x.y do; end; end
diff --git a/test/prism/fixtures/seattlerb/defs_comments.txt b/test/prism/fixtures/seattlerb/defs_comments.txt
new file mode 100644
index 0000000000..52b9b4a6b3
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defs_comments.txt
@@ -0,0 +1,5 @@
+# blah 1
+# blah 2
+
+def self.blah
+end
diff --git a/test/prism/fixtures/seattlerb/defs_endless_command.txt b/test/prism/fixtures/seattlerb/defs_endless_command.txt
new file mode 100644
index 0000000000..3b605657de
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defs_endless_command.txt
@@ -0,0 +1 @@
+def x.some_method = other_method 42
diff --git a/test/prism/fixtures/seattlerb/defs_endless_command_rescue.txt b/test/prism/fixtures/seattlerb/defs_endless_command_rescue.txt
new file mode 100644
index 0000000000..6ece366db0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defs_endless_command_rescue.txt
@@ -0,0 +1 @@
+def x.some_method = other_method 42 rescue 24
diff --git a/test/prism/fixtures/seattlerb/defs_kwarg.txt b/test/prism/fixtures/seattlerb/defs_kwarg.txt
new file mode 100644
index 0000000000..59970a371e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defs_kwarg.txt
@@ -0,0 +1,2 @@
+def self.a b: 1
+end
diff --git a/test/prism/fixtures/seattlerb/defs_oneliner.txt b/test/prism/fixtures/seattlerb/defs_oneliner.txt
new file mode 100644
index 0000000000..1867edcfbf
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defs_oneliner.txt
@@ -0,0 +1 @@
+def self.exec(cmd) = system(cmd)
diff --git a/test/prism/fixtures/seattlerb/defs_oneliner_eq2.txt b/test/prism/fixtures/seattlerb/defs_oneliner_eq2.txt
new file mode 100644
index 0000000000..1e55f68bf3
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defs_oneliner_eq2.txt
@@ -0,0 +1,3 @@
+class X
+ def self.==(o) = 42
+end
diff --git a/test/prism/fixtures/seattlerb/defs_oneliner_rescue.txt b/test/prism/fixtures/seattlerb/defs_oneliner_rescue.txt
new file mode 100644
index 0000000000..7a04012b8f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/defs_oneliner_rescue.txt
@@ -0,0 +1,13 @@
+def self.exec(cmd)
+ system(cmd)
+rescue
+ nil
+end
+
+
+def self.exec(cmd)
+ system(cmd) rescue nil
+end
+
+
+def self.exec(cmd) = system(cmd) rescue nil
diff --git a/test/prism/fixtures/seattlerb/difficult0_.txt b/test/prism/fixtures/seattlerb/difficult0_.txt
new file mode 100644
index 0000000000..5c73907cae
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult0_.txt
@@ -0,0 +1,4 @@
+p <<-END+'b
+ a
+ END
+ c'+'d'
diff --git a/test/prism/fixtures/seattlerb/difficult1_line_numbers.txt b/test/prism/fixtures/seattlerb/difficult1_line_numbers.txt
new file mode 100644
index 0000000000..8008127dc9
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult1_line_numbers.txt
@@ -0,0 +1,13 @@
+if true
+ p 1
+ a.b 2
+ c.d 3, 4
+ e.f 5
+ g.h 6, 7
+ p(1)
+ a.b(2)
+ c.d(3, 4)
+ e.f(5)
+ g.h(6, 7)
+end
+
diff --git a/test/prism/fixtures/seattlerb/difficult1_line_numbers2.txt b/test/prism/fixtures/seattlerb/difficult1_line_numbers2.txt
new file mode 100644
index 0000000000..1964562416
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult1_line_numbers2.txt
@@ -0,0 +1,8 @@
+if true then
+ p("a")
+ b = 1
+ p b
+ c =1
+end
+a
+
diff --git a/test/prism/fixtures/seattlerb/difficult2_.txt b/test/prism/fixtures/seattlerb/difficult2_.txt
new file mode 100644
index 0000000000..3259097492
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult2_.txt
@@ -0,0 +1,2 @@
+1 ? b('') : 2
+a d: 3
diff --git a/test/prism/fixtures/seattlerb/difficult3_.txt b/test/prism/fixtures/seattlerb/difficult3_.txt
new file mode 100644
index 0000000000..9f95860b82
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult3_.txt
@@ -0,0 +1 @@
+f { |a, (b, *c)| }
diff --git a/test/prism/fixtures/seattlerb/difficult3_2.txt b/test/prism/fixtures/seattlerb/difficult3_2.txt
new file mode 100644
index 0000000000..8abfe3f634
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult3_2.txt
@@ -0,0 +1 @@
+f { |*a, b| }
diff --git a/test/prism/fixtures/seattlerb/difficult3_3.txt b/test/prism/fixtures/seattlerb/difficult3_3.txt
new file mode 100644
index 0000000000..6f43ab7b1d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult3_3.txt
@@ -0,0 +1 @@
+f { |*a, b, &c| }
diff --git a/test/prism/fixtures/seattlerb/difficult3_4.txt b/test/prism/fixtures/seattlerb/difficult3_4.txt
new file mode 100644
index 0000000000..7070e1e964
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult3_4.txt
@@ -0,0 +1 @@
+a=b ? true: false
diff --git a/test/prism/fixtures/seattlerb/difficult3_5.txt b/test/prism/fixtures/seattlerb/difficult3_5.txt
new file mode 100644
index 0000000000..6d52692481
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult3_5.txt
@@ -0,0 +1 @@
+f ->() { g do end }
diff --git a/test/prism/fixtures/seattlerb/difficult3__10.txt b/test/prism/fixtures/seattlerb/difficult3__10.txt
new file mode 100644
index 0000000000..89974f5114
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult3__10.txt
@@ -0,0 +1 @@
+f { |a, (*b, c)| }
diff --git a/test/prism/fixtures/seattlerb/difficult3__11.txt b/test/prism/fixtures/seattlerb/difficult3__11.txt
new file mode 100644
index 0000000000..911d037961
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult3__11.txt
@@ -0,0 +1 @@
+f { |a, (*)| }
diff --git a/test/prism/fixtures/seattlerb/difficult3__12.txt b/test/prism/fixtures/seattlerb/difficult3__12.txt
new file mode 100644
index 0000000000..2405a80ec1
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult3__12.txt
@@ -0,0 +1 @@
+f { |a, (*, b)| }
diff --git a/test/prism/fixtures/seattlerb/difficult3__6.txt b/test/prism/fixtures/seattlerb/difficult3__6.txt
new file mode 100644
index 0000000000..3a45ae86fb
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult3__6.txt
@@ -0,0 +1 @@
+f { |a, (b, *c, d)| }
diff --git a/test/prism/fixtures/seattlerb/difficult3__7.txt b/test/prism/fixtures/seattlerb/difficult3__7.txt
new file mode 100644
index 0000000000..55272a1fc4
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult3__7.txt
@@ -0,0 +1 @@
+f { |a, (b, *)| }
diff --git a/test/prism/fixtures/seattlerb/difficult3__8.txt b/test/prism/fixtures/seattlerb/difficult3__8.txt
new file mode 100644
index 0000000000..76740db4ff
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult3__8.txt
@@ -0,0 +1 @@
+f { |a, (b, *, c)| }
diff --git a/test/prism/fixtures/seattlerb/difficult3__9.txt b/test/prism/fixtures/seattlerb/difficult3__9.txt
new file mode 100644
index 0000000000..b65f7fd052
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult3__9.txt
@@ -0,0 +1 @@
+f { |a, (*b)| }
diff --git a/test/prism/fixtures/seattlerb/difficult4__leading_dots.txt b/test/prism/fixtures/seattlerb/difficult4__leading_dots.txt
new file mode 100644
index 0000000000..332dc8225c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult4__leading_dots.txt
@@ -0,0 +1,2 @@
+a
+.b
diff --git a/test/prism/fixtures/seattlerb/difficult4__leading_dots2.txt b/test/prism/fixtures/seattlerb/difficult4__leading_dots2.txt
new file mode 100644
index 0000000000..fe73f641fe
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult4__leading_dots2.txt
@@ -0,0 +1,2 @@
+1
+..3
diff --git a/test/prism/fixtures/seattlerb/difficult6_.txt b/test/prism/fixtures/seattlerb/difficult6_.txt
new file mode 100644
index 0000000000..7396a9a76f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult6_.txt
@@ -0,0 +1 @@
+->(a, b=nil) { p [a, b] }
diff --git a/test/prism/fixtures/seattlerb/difficult6__7.txt b/test/prism/fixtures/seattlerb/difficult6__7.txt
new file mode 100644
index 0000000000..048358bbdc
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult6__7.txt
@@ -0,0 +1 @@
+a.b (1) {c}
diff --git a/test/prism/fixtures/seattlerb/difficult6__8.txt b/test/prism/fixtures/seattlerb/difficult6__8.txt
new file mode 100644
index 0000000000..ba1cbc235d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult6__8.txt
@@ -0,0 +1 @@
+a::b (1) {c}
diff --git a/test/prism/fixtures/seattlerb/difficult7_.txt b/test/prism/fixtures/seattlerb/difficult7_.txt
new file mode 100644
index 0000000000..112b75c5f2
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/difficult7_.txt
@@ -0,0 +1,5 @@
+ {
+ a: lambda { b ? c() : d },
+ e: nil,
+ }
+
diff --git a/test/prism/fixtures/seattlerb/do_bug.txt b/test/prism/fixtures/seattlerb/do_bug.txt
new file mode 100644
index 0000000000..a274e72baf
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/do_bug.txt
@@ -0,0 +1,4 @@
+a 1
+a.b do |c|
+ # do nothing
+end
diff --git a/test/prism/fixtures/seattlerb/do_lambda.txt b/test/prism/fixtures/seattlerb/do_lambda.txt
new file mode 100644
index 0000000000..06d2a38d30
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/do_lambda.txt
@@ -0,0 +1 @@
+->() do end
diff --git a/test/prism/fixtures/seattlerb/dot2_nil__26.txt b/test/prism/fixtures/seattlerb/dot2_nil__26.txt
new file mode 100644
index 0000000000..cc070eb69f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/dot2_nil__26.txt
@@ -0,0 +1 @@
+a..
diff --git a/test/prism/fixtures/seattlerb/dot3_nil__26.txt b/test/prism/fixtures/seattlerb/dot3_nil__26.txt
new file mode 100644
index 0000000000..7f4aef7af7
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/dot3_nil__26.txt
@@ -0,0 +1 @@
+a...
diff --git a/test/prism/fixtures/seattlerb/dstr_evstr.txt b/test/prism/fixtures/seattlerb/dstr_evstr.txt
new file mode 100644
index 0000000000..5fe4a858c1
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/dstr_evstr.txt
@@ -0,0 +1 @@
+"#{'a'}#{b}"
diff --git a/test/prism/fixtures/seattlerb/dstr_evstr_empty_end.txt b/test/prism/fixtures/seattlerb/dstr_evstr_empty_end.txt
new file mode 100644
index 0000000000..7a55030fa8
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/dstr_evstr_empty_end.txt
@@ -0,0 +1 @@
+:"#{field}"
diff --git a/test/prism/fixtures/seattlerb/dstr_lex_state.txt b/test/prism/fixtures/seattlerb/dstr_lex_state.txt
new file mode 100644
index 0000000000..6cac1d8e95
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/dstr_lex_state.txt
@@ -0,0 +1 @@
+"#{p:a}"
diff --git a/test/prism/fixtures/seattlerb/dstr_str.txt b/test/prism/fixtures/seattlerb/dstr_str.txt
new file mode 100644
index 0000000000..226ce2b191
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/dstr_str.txt
@@ -0,0 +1 @@
+"#{'a'} b"
diff --git a/test/prism/fixtures/seattlerb/dsym_esc_to_sym.txt b/test/prism/fixtures/seattlerb/dsym_esc_to_sym.txt
new file mode 100644
index 0000000000..e5781453c1
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/dsym_esc_to_sym.txt
@@ -0,0 +1 @@
+:"Variet\303\240"
diff --git a/test/prism/fixtures/seattlerb/dsym_to_sym.txt b/test/prism/fixtures/seattlerb/dsym_to_sym.txt
new file mode 100644
index 0000000000..813c90342c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/dsym_to_sym.txt
@@ -0,0 +1,3 @@
+alias :"<<" :">>"
+
+alias :<< :>>
diff --git a/test/prism/fixtures/seattlerb/eq_begin_line_numbers.txt b/test/prism/fixtures/seattlerb/eq_begin_line_numbers.txt
new file mode 100644
index 0000000000..aae82e1207
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/eq_begin_line_numbers.txt
@@ -0,0 +1,6 @@
+1
+=begin
+comment
+comment
+=end
+2
diff --git a/test/prism/fixtures/seattlerb/eq_begin_why_wont_people_use_their_spacebar.txt b/test/prism/fixtures/seattlerb/eq_begin_why_wont_people_use_their_spacebar.txt
new file mode 100644
index 0000000000..88ff599e91
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/eq_begin_why_wont_people_use_their_spacebar.txt
@@ -0,0 +1,3 @@
+h[k]=begin
+ 42
+ end
diff --git a/test/prism/fixtures/seattlerb/evstr_evstr.txt b/test/prism/fixtures/seattlerb/evstr_evstr.txt
new file mode 100644
index 0000000000..cf0b5ee873
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/evstr_evstr.txt
@@ -0,0 +1 @@
+"#{a}#{b}"
diff --git a/test/prism/fixtures/seattlerb/evstr_str.txt b/test/prism/fixtures/seattlerb/evstr_str.txt
new file mode 100644
index 0000000000..5746909b19
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/evstr_str.txt
@@ -0,0 +1 @@
+"#{a} b"
diff --git a/test/prism/fixtures/seattlerb/expr_not_bang.txt b/test/prism/fixtures/seattlerb/expr_not_bang.txt
new file mode 100644
index 0000000000..6ed80c76d3
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/expr_not_bang.txt
@@ -0,0 +1 @@
+! a b
diff --git a/test/prism/fixtures/seattlerb/f_kw.txt b/test/prism/fixtures/seattlerb/f_kw.txt
new file mode 100644
index 0000000000..4dd42662b8
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/f_kw.txt
@@ -0,0 +1 @@
+def x k:42; end
diff --git a/test/prism/fixtures/seattlerb/f_kw__required.txt b/test/prism/fixtures/seattlerb/f_kw__required.txt
new file mode 100644
index 0000000000..2e1e258ff0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/f_kw__required.txt
@@ -0,0 +1 @@
+def x k:; end
diff --git a/test/prism/fixtures/seattlerb/flip2_env_lvar.txt b/test/prism/fixtures/seattlerb/flip2_env_lvar.txt
new file mode 100644
index 0000000000..619b2c915e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/flip2_env_lvar.txt
@@ -0,0 +1 @@
+if a..b then end
diff --git a/test/prism/fixtures/seattlerb/float_with_if_modifier.txt b/test/prism/fixtures/seattlerb/float_with_if_modifier.txt
new file mode 100644
index 0000000000..6a62d4a308
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/float_with_if_modifier.txt
@@ -0,0 +1 @@
+1.0if true
diff --git a/test/prism/fixtures/seattlerb/heredoc__backslash_dos_format.txt b/test/prism/fixtures/seattlerb/heredoc__backslash_dos_format.txt
new file mode 100644
index 0000000000..cfbcb2a11d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc__backslash_dos_format.txt
@@ -0,0 +1,5 @@
+str = <<-XXX
+before\
+after
+XXX
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_backslash_nl.txt b/test/prism/fixtures/seattlerb/heredoc_backslash_nl.txt
new file mode 100644
index 0000000000..0cc5b35fd5
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_backslash_nl.txt
@@ -0,0 +1,8 @@
+" why would someone do this? \
+ blah
+"
+
+<<-DESC
+ why would someone do this? \
+ blah
+DESC
diff --git a/test/prism/fixtures/seattlerb/heredoc_bad_hex_escape.txt b/test/prism/fixtures/seattlerb/heredoc_bad_hex_escape.txt
new file mode 100644
index 0000000000..2c386cc6a9
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_bad_hex_escape.txt
@@ -0,0 +1,3 @@
+s = <<eos
+a\xE9b
+eos
diff --git a/test/prism/fixtures/seattlerb/heredoc_bad_oct_escape.txt b/test/prism/fixtures/seattlerb/heredoc_bad_oct_escape.txt
new file mode 100644
index 0000000000..235a041e90
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_bad_oct_escape.txt
@@ -0,0 +1,5 @@
+s = <<-EOS
+a\247b
+cöd
+EOS
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_comma_arg.txt b/test/prism/fixtures/seattlerb/heredoc_comma_arg.txt
new file mode 100644
index 0000000000..c230b12f65
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_comma_arg.txt
@@ -0,0 +1,7 @@
+[" some text
+",]
+
+[<<-FILE,
+ some text
+FILE
+]
diff --git a/test/prism/fixtures/seattlerb/heredoc_lineno.txt b/test/prism/fixtures/seattlerb/heredoc_lineno.txt
new file mode 100644
index 0000000000..73a2e3806b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_lineno.txt
@@ -0,0 +1,7 @@
+c = <<'CCC'
+line2
+line3
+line4
+CCC
+
+d = 42
diff --git a/test/prism/fixtures/seattlerb/heredoc_nested.txt b/test/prism/fixtures/seattlerb/heredoc_nested.txt
new file mode 100644
index 0000000000..508d6d3c05
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_nested.txt
@@ -0,0 +1,7 @@
+[<<A,
+#{<<B}
+b
+B
+a
+A
+0]
diff --git a/test/prism/fixtures/seattlerb/heredoc_squiggly.txt b/test/prism/fixtures/seattlerb/heredoc_squiggly.txt
new file mode 100644
index 0000000000..e630ff62b4
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_squiggly.txt
@@ -0,0 +1,7 @@
+a = <<~"EOF"
+ x
+ y
+ z
+ EOF
+
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_squiggly_blank_line_plus_interpolation.txt b/test/prism/fixtures/seattlerb/heredoc_squiggly_blank_line_plus_interpolation.txt
new file mode 100644
index 0000000000..61b62157db
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_squiggly_blank_line_plus_interpolation.txt
@@ -0,0 +1,4 @@
+a = foo(<<~EOF.chop)
+
+ #{bar}baz
+ EOF
diff --git a/test/prism/fixtures/seattlerb/heredoc_squiggly_blank_lines.txt b/test/prism/fixtures/seattlerb/heredoc_squiggly_blank_lines.txt
new file mode 100644
index 0000000000..0d89134c87
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_squiggly_blank_lines.txt
@@ -0,0 +1,7 @@
+a = <<~EOF
+ x
+
+ z
+EOF
+
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_squiggly_empty.txt b/test/prism/fixtures/seattlerb/heredoc_squiggly_empty.txt
new file mode 100644
index 0000000000..4602d757fb
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_squiggly_empty.txt
@@ -0,0 +1,2 @@
+<<~A
+A
diff --git a/test/prism/fixtures/seattlerb/heredoc_squiggly_interp.txt b/test/prism/fixtures/seattlerb/heredoc_squiggly_interp.txt
new file mode 100644
index 0000000000..47ff3c9070
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_squiggly_interp.txt
@@ -0,0 +1,5 @@
+a = <<~EOF
+ w
+ x#{42} y
+ z
+ EOF
diff --git a/test/prism/fixtures/seattlerb/heredoc_squiggly_no_indent.txt b/test/prism/fixtures/seattlerb/heredoc_squiggly_no_indent.txt
new file mode 100644
index 0000000000..7076f6ef71
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_squiggly_no_indent.txt
@@ -0,0 +1,3 @@
+<<~A
+a
+A
diff --git a/test/prism/fixtures/seattlerb/heredoc_squiggly_tabs.txt b/test/prism/fixtures/seattlerb/heredoc_squiggly_tabs.txt
new file mode 100644
index 0000000000..b193f0473b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_squiggly_tabs.txt
@@ -0,0 +1,6 @@
+a = <<~"EOF"
+ blah blah
+ blah blah
+ EOF
+
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_squiggly_tabs_extra.txt b/test/prism/fixtures/seattlerb/heredoc_squiggly_tabs_extra.txt
new file mode 100644
index 0000000000..5b75dd2b59
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_squiggly_tabs_extra.txt
@@ -0,0 +1,6 @@
+a = <<~"EOF"
+ blah blah
+ blah blah
+ EOF
+
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_squiggly_visually_blank_lines.txt b/test/prism/fixtures/seattlerb/heredoc_squiggly_visually_blank_lines.txt
new file mode 100644
index 0000000000..3f9198296d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_squiggly_visually_blank_lines.txt
@@ -0,0 +1,7 @@
+a = <<~EOF
+ x
+
+ z
+EOF
+
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_trailing_slash_continued_call.txt b/test/prism/fixtures/seattlerb/heredoc_trailing_slash_continued_call.txt
new file mode 100644
index 0000000000..12c8fac126
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_trailing_slash_continued_call.txt
@@ -0,0 +1,4 @@
+<<END\
+blah
+END
+.strip
diff --git a/test/prism/fixtures/seattlerb/heredoc_unicode.txt b/test/prism/fixtures/seattlerb/heredoc_unicode.txt
new file mode 100644
index 0000000000..216a5cfe24
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_unicode.txt
@@ -0,0 +1,4 @@
+<<OOTPÜT
+.
+OOTPÜT
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_with_carriage_return_escapes.txt b/test/prism/fixtures/seattlerb/heredoc_with_carriage_return_escapes.txt
new file mode 100644
index 0000000000..cb4967d154
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_with_carriage_return_escapes.txt
@@ -0,0 +1,5 @@
+<<EOS
+foo\rbar
+baz\r
+EOS
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_with_carriage_return_escapes_windows.txt b/test/prism/fixtures/seattlerb/heredoc_with_carriage_return_escapes_windows.txt
new file mode 100644
index 0000000000..75ed936b5d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_with_carriage_return_escapes_windows.txt
@@ -0,0 +1,5 @@
+<<EOS
+foo\rbar
+baz\r
+EOS
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_horrible_mix.txt b/test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_horrible_mix.txt
new file mode 100644
index 0000000000..1c58c05cc5
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_horrible_mix.txt
@@ -0,0 +1,4 @@
+<<'eot'
+body
+eot
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_returns.txt b/test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_returns.txt
new file mode 100644
index 0000000000..706cb0d5c0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_returns.txt
@@ -0,0 +1,5 @@
+<<EOS
+foo bar
+baz
+EOS
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_returns_windows.txt b/test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_returns_windows.txt
new file mode 100644
index 0000000000..8ed84799b1
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_returns_windows.txt
@@ -0,0 +1,5 @@
+<<EOS
+foo bar
+baz
+EOS
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes.txt b/test/prism/fixtures/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes.txt
new file mode 100644
index 0000000000..250e606f45
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes.txt
@@ -0,0 +1,4 @@
+<<EOS
+foo\r#@bar
+EOS
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes_windows.txt b/test/prism/fixtures/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes_windows.txt
new file mode 100644
index 0000000000..12f97aff5e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes_windows.txt
@@ -0,0 +1,4 @@
+<<EOS
+foo\r#@bar
+EOS
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_with_not_global_interpolation.txt b/test/prism/fixtures/seattlerb/heredoc_with_not_global_interpolation.txt
new file mode 100644
index 0000000000..f94c2c9e27
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_with_not_global_interpolation.txt
@@ -0,0 +1,3 @@
+<<-HEREDOC
+#${
+HEREDOC
diff --git a/test/prism/fixtures/seattlerb/heredoc_with_only_carriage_returns.txt b/test/prism/fixtures/seattlerb/heredoc_with_only_carriage_returns.txt
new file mode 100644
index 0000000000..468ba85cf7
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_with_only_carriage_returns.txt
@@ -0,0 +1,6 @@
+<<EOS
+
+
+\r
+EOS
+
diff --git a/test/prism/fixtures/seattlerb/heredoc_with_only_carriage_returns_windows.txt b/test/prism/fixtures/seattlerb/heredoc_with_only_carriage_returns_windows.txt
new file mode 100644
index 0000000000..e973eff110
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/heredoc_with_only_carriage_returns_windows.txt
@@ -0,0 +1,6 @@
+<<EOS
+
+
+\r
+EOS
+
diff --git a/test/prism/fixtures/seattlerb/if_elsif.txt b/test/prism/fixtures/seattlerb/if_elsif.txt
new file mode 100644
index 0000000000..bc1c0a2b3d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/if_elsif.txt
@@ -0,0 +1 @@
+if 1; elsif 2; end
diff --git a/test/prism/fixtures/seattlerb/if_symbol.txt b/test/prism/fixtures/seattlerb/if_symbol.txt
new file mode 100644
index 0000000000..8d6e958ede
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/if_symbol.txt
@@ -0,0 +1 @@
+if f :x; end
diff --git a/test/prism/fixtures/seattlerb/in_expr_no_case.txt b/test/prism/fixtures/seattlerb/in_expr_no_case.txt
new file mode 100644
index 0000000000..40db7f868b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/in_expr_no_case.txt
@@ -0,0 +1 @@
+'woot' in String
diff --git a/test/prism/fixtures/seattlerb/index_0.txt b/test/prism/fixtures/seattlerb/index_0.txt
new file mode 100644
index 0000000000..050d4566ba
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/index_0.txt
@@ -0,0 +1 @@
+a[] = b
diff --git a/test/prism/fixtures/seattlerb/index_0_opasgn.txt b/test/prism/fixtures/seattlerb/index_0_opasgn.txt
new file mode 100644
index 0000000000..7189f0c3ea
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/index_0_opasgn.txt
@@ -0,0 +1 @@
+a[] += b
diff --git a/test/prism/fixtures/seattlerb/integer_with_if_modifier.txt b/test/prism/fixtures/seattlerb/integer_with_if_modifier.txt
new file mode 100644
index 0000000000..bf2f621e92
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/integer_with_if_modifier.txt
@@ -0,0 +1 @@
+1_234if true
diff --git a/test/prism/fixtures/seattlerb/interpolated_symbol_array_line_breaks.txt b/test/prism/fixtures/seattlerb/interpolated_symbol_array_line_breaks.txt
new file mode 100644
index 0000000000..f4c7cb9662
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/interpolated_symbol_array_line_breaks.txt
@@ -0,0 +1,5 @@
+%I(
+a
+b
+)
+1
diff --git a/test/prism/fixtures/seattlerb/interpolated_word_array_line_breaks.txt b/test/prism/fixtures/seattlerb/interpolated_word_array_line_breaks.txt
new file mode 100644
index 0000000000..d52b4789cf
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/interpolated_word_array_line_breaks.txt
@@ -0,0 +1,5 @@
+%W(
+a
+b
+)
+1
diff --git a/test/prism/fixtures/seattlerb/iter_args_1.txt b/test/prism/fixtures/seattlerb/iter_args_1.txt
new file mode 100644
index 0000000000..c890ef62c3
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_1.txt
@@ -0,0 +1 @@
+f { |a,b| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_10_1.txt b/test/prism/fixtures/seattlerb/iter_args_10_1.txt
new file mode 100644
index 0000000000..3f558c5392
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_10_1.txt
@@ -0,0 +1 @@
+f { |a, b = 42, *c| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_10_2.txt b/test/prism/fixtures/seattlerb/iter_args_10_2.txt
new file mode 100644
index 0000000000..4158e79d14
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_10_2.txt
@@ -0,0 +1 @@
+f { |a, b = 42, *c, &d| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_11_1.txt b/test/prism/fixtures/seattlerb/iter_args_11_1.txt
new file mode 100644
index 0000000000..f86175c1a0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_11_1.txt
@@ -0,0 +1 @@
+f { |a, b = 42, *c, d| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_11_2.txt b/test/prism/fixtures/seattlerb/iter_args_11_2.txt
new file mode 100644
index 0000000000..e4b017e44a
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_11_2.txt
@@ -0,0 +1 @@
+f { |a, b = 42, *c, d, &e| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_2__19.txt b/test/prism/fixtures/seattlerb/iter_args_2__19.txt
new file mode 100644
index 0000000000..84dd744243
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_2__19.txt
@@ -0,0 +1 @@
+f { |(a, b)| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_3.txt b/test/prism/fixtures/seattlerb/iter_args_3.txt
new file mode 100644
index 0000000000..261968ff13
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_3.txt
@@ -0,0 +1 @@
+f { |a, (b, c), d| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_4.txt b/test/prism/fixtures/seattlerb/iter_args_4.txt
new file mode 100644
index 0000000000..7db4d43ad3
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_4.txt
@@ -0,0 +1 @@
+f { |a, *b, c| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_5.txt b/test/prism/fixtures/seattlerb/iter_args_5.txt
new file mode 100644
index 0000000000..088fcdfcc5
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_5.txt
@@ -0,0 +1 @@
+f { |a, &b| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_6.txt b/test/prism/fixtures/seattlerb/iter_args_6.txt
new file mode 100644
index 0000000000..e980ec064b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_6.txt
@@ -0,0 +1 @@
+f { |a, b=42, c| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_7_1.txt b/test/prism/fixtures/seattlerb/iter_args_7_1.txt
new file mode 100644
index 0000000000..e1dbf4b312
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_7_1.txt
@@ -0,0 +1 @@
+f { |a = 42, *b| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_7_2.txt b/test/prism/fixtures/seattlerb/iter_args_7_2.txt
new file mode 100644
index 0000000000..e46e78e00e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_7_2.txt
@@ -0,0 +1 @@
+f { |a = 42, *b, &c| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_8_1.txt b/test/prism/fixtures/seattlerb/iter_args_8_1.txt
new file mode 100644
index 0000000000..a0ec82ea5b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_8_1.txt
@@ -0,0 +1 @@
+f { |a = 42, *b, c| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_8_2.txt b/test/prism/fixtures/seattlerb/iter_args_8_2.txt
new file mode 100644
index 0000000000..a1839fe706
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_8_2.txt
@@ -0,0 +1 @@
+f { |a = 42, *b, c, &d| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_9_1.txt b/test/prism/fixtures/seattlerb/iter_args_9_1.txt
new file mode 100644
index 0000000000..13e5b20fe7
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_9_1.txt
@@ -0,0 +1 @@
+f { |a = 42, b| }
diff --git a/test/prism/fixtures/seattlerb/iter_args_9_2.txt b/test/prism/fixtures/seattlerb/iter_args_9_2.txt
new file mode 100644
index 0000000000..83f6e1e029
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_args_9_2.txt
@@ -0,0 +1 @@
+f { |a = 42, b, &c| }
diff --git a/test/prism/fixtures/seattlerb/iter_kwarg.txt b/test/prism/fixtures/seattlerb/iter_kwarg.txt
new file mode 100644
index 0000000000..d4296cad76
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_kwarg.txt
@@ -0,0 +1 @@
+a { |b: 1| }
diff --git a/test/prism/fixtures/seattlerb/iter_kwarg_kwsplat.txt b/test/prism/fixtures/seattlerb/iter_kwarg_kwsplat.txt
new file mode 100644
index 0000000000..dd0ea13a6f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/iter_kwarg_kwsplat.txt
@@ -0,0 +1 @@
+a { |b: 1, **c| }
diff --git a/test/prism/fixtures/seattlerb/label_vs_string.txt b/test/prism/fixtures/seattlerb/label_vs_string.txt
new file mode 100644
index 0000000000..27ba8b64de
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/label_vs_string.txt
@@ -0,0 +1,2 @@
+_buf << ':
+'
diff --git a/test/prism/fixtures/seattlerb/lambda_do_vs_brace.txt b/test/prism/fixtures/seattlerb/lambda_do_vs_brace.txt
new file mode 100644
index 0000000000..bbf663a46a
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/lambda_do_vs_brace.txt
@@ -0,0 +1,7 @@
+f -> do end
+
+f -> {}
+
+f ->() do end
+
+f ->() {}
diff --git a/test/prism/fixtures/seattlerb/lasgn_arg_rescue_arg.txt b/test/prism/fixtures/seattlerb/lasgn_arg_rescue_arg.txt
new file mode 100644
index 0000000000..0dad496c28
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/lasgn_arg_rescue_arg.txt
@@ -0,0 +1 @@
+a = 1 rescue 2
diff --git a/test/prism/fixtures/seattlerb/lasgn_call_bracket_rescue_arg.txt b/test/prism/fixtures/seattlerb/lasgn_call_bracket_rescue_arg.txt
new file mode 100644
index 0000000000..3f63c0b748
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/lasgn_call_bracket_rescue_arg.txt
@@ -0,0 +1 @@
+a = b(1) rescue 2
diff --git a/test/prism/fixtures/seattlerb/lasgn_call_nobracket_rescue_arg.txt b/test/prism/fixtures/seattlerb/lasgn_call_nobracket_rescue_arg.txt
new file mode 100644
index 0000000000..0e86f1587d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/lasgn_call_nobracket_rescue_arg.txt
@@ -0,0 +1 @@
+a = b 1 rescue 2
diff --git a/test/prism/fixtures/seattlerb/lasgn_command.txt b/test/prism/fixtures/seattlerb/lasgn_command.txt
new file mode 100644
index 0000000000..aca35b880c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/lasgn_command.txt
@@ -0,0 +1 @@
+a = b.c 1
diff --git a/test/prism/fixtures/seattlerb/lasgn_env.txt b/test/prism/fixtures/seattlerb/lasgn_env.txt
new file mode 100644
index 0000000000..aec10273e5
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/lasgn_env.txt
@@ -0,0 +1 @@
+a = 42
diff --git a/test/prism/fixtures/seattlerb/lasgn_ivar_env.txt b/test/prism/fixtures/seattlerb/lasgn_ivar_env.txt
new file mode 100644
index 0000000000..2fa8471c01
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/lasgn_ivar_env.txt
@@ -0,0 +1 @@
+@a = 42
diff --git a/test/prism/fixtures/seattlerb/lasgn_lasgn_command_call.txt b/test/prism/fixtures/seattlerb/lasgn_lasgn_command_call.txt
new file mode 100644
index 0000000000..5147131852
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/lasgn_lasgn_command_call.txt
@@ -0,0 +1 @@
+a = b = c 1
diff --git a/test/prism/fixtures/seattlerb/lasgn_middle_splat.txt b/test/prism/fixtures/seattlerb/lasgn_middle_splat.txt
new file mode 100644
index 0000000000..bb378ca680
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/lasgn_middle_splat.txt
@@ -0,0 +1 @@
+a = b, *c, d
diff --git a/test/prism/fixtures/seattlerb/magic_encoding_comment.txt b/test/prism/fixtures/seattlerb/magic_encoding_comment.txt
new file mode 100644
index 0000000000..a02711ea05
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/magic_encoding_comment.txt
@@ -0,0 +1,4 @@
+# encoding: utf-8
+class ExampleUTF8ClassNameVarietà; def self.è; così = :però; end
+end
+
diff --git a/test/prism/fixtures/seattlerb/masgn_anon_splat_arg.txt b/test/prism/fixtures/seattlerb/masgn_anon_splat_arg.txt
new file mode 100644
index 0000000000..b796a742ed
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_anon_splat_arg.txt
@@ -0,0 +1 @@
+*, a = b
diff --git a/test/prism/fixtures/seattlerb/masgn_arg_colon_arg.txt b/test/prism/fixtures/seattlerb/masgn_arg_colon_arg.txt
new file mode 100644
index 0000000000..e0919793d4
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_arg_colon_arg.txt
@@ -0,0 +1 @@
+a, b::c = d
diff --git a/test/prism/fixtures/seattlerb/masgn_arg_ident.txt b/test/prism/fixtures/seattlerb/masgn_arg_ident.txt
new file mode 100644
index 0000000000..45f248d854
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_arg_ident.txt
@@ -0,0 +1 @@
+a, b.C = d
diff --git a/test/prism/fixtures/seattlerb/masgn_arg_splat_arg.txt b/test/prism/fixtures/seattlerb/masgn_arg_splat_arg.txt
new file mode 100644
index 0000000000..05fe7c4d5f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_arg_splat_arg.txt
@@ -0,0 +1 @@
+a, *b, c = d
diff --git a/test/prism/fixtures/seattlerb/masgn_colon2.txt b/test/prism/fixtures/seattlerb/masgn_colon2.txt
new file mode 100644
index 0000000000..4e4f838d7d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_colon2.txt
@@ -0,0 +1 @@
+a, b::C = 1, 2
diff --git a/test/prism/fixtures/seattlerb/masgn_colon3.txt b/test/prism/fixtures/seattlerb/masgn_colon3.txt
new file mode 100644
index 0000000000..46098ba8c5
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_colon3.txt
@@ -0,0 +1 @@
+::A, ::B = 1, 2
diff --git a/test/prism/fixtures/seattlerb/masgn_command_call.txt b/test/prism/fixtures/seattlerb/masgn_command_call.txt
new file mode 100644
index 0000000000..6da01e8a31
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_command_call.txt
@@ -0,0 +1 @@
+a, = b.c 1
diff --git a/test/prism/fixtures/seattlerb/masgn_double_paren.txt b/test/prism/fixtures/seattlerb/masgn_double_paren.txt
new file mode 100644
index 0000000000..ffac0a85a3
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_double_paren.txt
@@ -0,0 +1 @@
+((a,b))=c
diff --git a/test/prism/fixtures/seattlerb/masgn_lhs_splat.txt b/test/prism/fixtures/seattlerb/masgn_lhs_splat.txt
new file mode 100644
index 0000000000..2419ef1671
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_lhs_splat.txt
@@ -0,0 +1 @@
+*a = 1, 2, 3
diff --git a/test/prism/fixtures/seattlerb/masgn_paren.txt b/test/prism/fixtures/seattlerb/masgn_paren.txt
new file mode 100644
index 0000000000..3889b9ff48
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_paren.txt
@@ -0,0 +1 @@
+(a, b) = c.d
diff --git a/test/prism/fixtures/seattlerb/masgn_splat_arg.txt b/test/prism/fixtures/seattlerb/masgn_splat_arg.txt
new file mode 100644
index 0000000000..a7c91425b0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_splat_arg.txt
@@ -0,0 +1 @@
+*a, b = c
diff --git a/test/prism/fixtures/seattlerb/masgn_splat_arg_arg.txt b/test/prism/fixtures/seattlerb/masgn_splat_arg_arg.txt
new file mode 100644
index 0000000000..46196bd703
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_splat_arg_arg.txt
@@ -0,0 +1 @@
+*a, b, c = d
diff --git a/test/prism/fixtures/seattlerb/masgn_star.txt b/test/prism/fixtures/seattlerb/masgn_star.txt
new file mode 100644
index 0000000000..c5eea37de2
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_star.txt
@@ -0,0 +1 @@
+* = 1
diff --git a/test/prism/fixtures/seattlerb/masgn_var_star_var.txt b/test/prism/fixtures/seattlerb/masgn_var_star_var.txt
new file mode 100644
index 0000000000..04089c36ac
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/masgn_var_star_var.txt
@@ -0,0 +1 @@
+a, *, b = c
diff --git a/test/prism/fixtures/seattlerb/messy_op_asgn_lineno.txt b/test/prism/fixtures/seattlerb/messy_op_asgn_lineno.txt
new file mode 100644
index 0000000000..a7d1035ae3
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/messy_op_asgn_lineno.txt
@@ -0,0 +1 @@
+a (B::C *= d e)
diff --git a/test/prism/fixtures/seattlerb/method_call_assoc_trailing_comma.txt b/test/prism/fixtures/seattlerb/method_call_assoc_trailing_comma.txt
new file mode 100644
index 0000000000..86f0fbdfc9
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/method_call_assoc_trailing_comma.txt
@@ -0,0 +1 @@
+a.f(1=>2,)
diff --git a/test/prism/fixtures/seattlerb/method_call_trailing_comma.txt b/test/prism/fixtures/seattlerb/method_call_trailing_comma.txt
new file mode 100644
index 0000000000..1a155fba12
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/method_call_trailing_comma.txt
@@ -0,0 +1 @@
+a.f(1,)
diff --git a/test/prism/fixtures/seattlerb/mlhs_back_anonsplat.txt b/test/prism/fixtures/seattlerb/mlhs_back_anonsplat.txt
new file mode 100644
index 0000000000..7389b95563
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/mlhs_back_anonsplat.txt
@@ -0,0 +1 @@
+a, b, c, * = f
diff --git a/test/prism/fixtures/seattlerb/mlhs_back_splat.txt b/test/prism/fixtures/seattlerb/mlhs_back_splat.txt
new file mode 100644
index 0000000000..ec5d23889a
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/mlhs_back_splat.txt
@@ -0,0 +1 @@
+a, b, c, *s = f
diff --git a/test/prism/fixtures/seattlerb/mlhs_front_anonsplat.txt b/test/prism/fixtures/seattlerb/mlhs_front_anonsplat.txt
new file mode 100644
index 0000000000..67e569438c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/mlhs_front_anonsplat.txt
@@ -0,0 +1 @@
+*, x, y, z = f
diff --git a/test/prism/fixtures/seattlerb/mlhs_front_splat.txt b/test/prism/fixtures/seattlerb/mlhs_front_splat.txt
new file mode 100644
index 0000000000..dabadc382d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/mlhs_front_splat.txt
@@ -0,0 +1 @@
+*s, x, y, z = f
diff --git a/test/prism/fixtures/seattlerb/mlhs_keyword.txt b/test/prism/fixtures/seattlerb/mlhs_keyword.txt
new file mode 100644
index 0000000000..899e7f8ed3
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/mlhs_keyword.txt
@@ -0,0 +1 @@
+a.!=(true, true)
diff --git a/test/prism/fixtures/seattlerb/mlhs_mid_anonsplat.txt b/test/prism/fixtures/seattlerb/mlhs_mid_anonsplat.txt
new file mode 100644
index 0000000000..a70a7e531b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/mlhs_mid_anonsplat.txt
@@ -0,0 +1 @@
+a, b, c, *, x, y, z = f
diff --git a/test/prism/fixtures/seattlerb/mlhs_mid_splat.txt b/test/prism/fixtures/seattlerb/mlhs_mid_splat.txt
new file mode 100644
index 0000000000..2d23fd3966
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/mlhs_mid_splat.txt
@@ -0,0 +1 @@
+a, b, c, *s, x, y, z = f
diff --git a/test/prism/fixtures/seattlerb/mlhs_rescue.txt b/test/prism/fixtures/seattlerb/mlhs_rescue.txt
new file mode 100644
index 0000000000..b4c79ae32e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/mlhs_rescue.txt
@@ -0,0 +1 @@
+a, b = f rescue 42
diff --git a/test/prism/fixtures/seattlerb/module_comments.txt b/test/prism/fixtures/seattlerb/module_comments.txt
new file mode 100644
index 0000000000..cecb717c5b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/module_comments.txt
@@ -0,0 +1,10 @@
+# blah 1
+
+ # blah 2
+
+module X
+ # blah 3
+ def blah
+ # blah 4
+ end
+end
diff --git a/test/prism/fixtures/seattlerb/multiline_hash_declaration.txt b/test/prism/fixtures/seattlerb/multiline_hash_declaration.txt
new file mode 100644
index 0000000000..21530307d2
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/multiline_hash_declaration.txt
@@ -0,0 +1,8 @@
+f(state:
+ {
+})
+
+f(state: {
+})
+
+f(state: {})
diff --git a/test/prism/fixtures/seattlerb/non_interpolated_symbol_array_line_breaks.txt b/test/prism/fixtures/seattlerb/non_interpolated_symbol_array_line_breaks.txt
new file mode 100644
index 0000000000..1e14673f4e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/non_interpolated_symbol_array_line_breaks.txt
@@ -0,0 +1,5 @@
+%i(
+a
+b
+)
+1
diff --git a/test/prism/fixtures/seattlerb/non_interpolated_word_array_line_breaks.txt b/test/prism/fixtures/seattlerb/non_interpolated_word_array_line_breaks.txt
new file mode 100644
index 0000000000..79c1418770
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/non_interpolated_word_array_line_breaks.txt
@@ -0,0 +1,5 @@
+%w(
+a
+b
+)
+1
diff --git a/test/prism/fixtures/seattlerb/op_asgn_command_call.txt b/test/prism/fixtures/seattlerb/op_asgn_command_call.txt
new file mode 100644
index 0000000000..92c989cb0d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/op_asgn_command_call.txt
@@ -0,0 +1 @@
+a ||= b.c 2
diff --git a/test/prism/fixtures/seattlerb/op_asgn_dot_ident_command_call.txt b/test/prism/fixtures/seattlerb/op_asgn_dot_ident_command_call.txt
new file mode 100644
index 0000000000..89cfccda66
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/op_asgn_dot_ident_command_call.txt
@@ -0,0 +1 @@
+A.B ||= c 1
diff --git a/test/prism/fixtures/seattlerb/op_asgn_index_command_call.txt b/test/prism/fixtures/seattlerb/op_asgn_index_command_call.txt
new file mode 100644
index 0000000000..2bfced81fe
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/op_asgn_index_command_call.txt
@@ -0,0 +1 @@
+a[:b] ||= c 1, 2
diff --git a/test/prism/fixtures/seattlerb/op_asgn_primary_colon_const_command_call.txt b/test/prism/fixtures/seattlerb/op_asgn_primary_colon_const_command_call.txt
new file mode 100644
index 0000000000..a567f60e83
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/op_asgn_primary_colon_const_command_call.txt
@@ -0,0 +1 @@
+A::B *= c d
diff --git a/test/prism/fixtures/seattlerb/op_asgn_primary_colon_identifier1.txt b/test/prism/fixtures/seattlerb/op_asgn_primary_colon_identifier1.txt
new file mode 100644
index 0000000000..0784b49167
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/op_asgn_primary_colon_identifier1.txt
@@ -0,0 +1 @@
+A::b += 1
diff --git a/test/prism/fixtures/seattlerb/op_asgn_primary_colon_identifier_command_call.txt b/test/prism/fixtures/seattlerb/op_asgn_primary_colon_identifier_command_call.txt
new file mode 100644
index 0000000000..c0f16eb3c1
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/op_asgn_primary_colon_identifier_command_call.txt
@@ -0,0 +1 @@
+A::b *= c d
diff --git a/test/prism/fixtures/seattlerb/op_asgn_val_dot_ident_command_call.txt b/test/prism/fixtures/seattlerb/op_asgn_val_dot_ident_command_call.txt
new file mode 100644
index 0000000000..69057abf04
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/op_asgn_val_dot_ident_command_call.txt
@@ -0,0 +1 @@
+a.b ||= c 1
diff --git a/test/prism/fixtures/seattlerb/parse_def_special_name.txt b/test/prism/fixtures/seattlerb/parse_def_special_name.txt
new file mode 100644
index 0000000000..8d7d06c688
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_def_special_name.txt
@@ -0,0 +1 @@
+def next; end
diff --git a/test/prism/fixtures/seattlerb/parse_if_not_canonical.txt b/test/prism/fixtures/seattlerb/parse_if_not_canonical.txt
new file mode 100644
index 0000000000..1fd9bb7327
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_if_not_canonical.txt
@@ -0,0 +1,2 @@
+if not var.nil? then 'foo' else 'bar'
+end
diff --git a/test/prism/fixtures/seattlerb/parse_if_not_noncanonical.txt b/test/prism/fixtures/seattlerb/parse_if_not_noncanonical.txt
new file mode 100644
index 0000000000..1fd9bb7327
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_if_not_noncanonical.txt
@@ -0,0 +1,2 @@
+if not var.nil? then 'foo' else 'bar'
+end
diff --git a/test/prism/fixtures/seattlerb/parse_line_block.txt b/test/prism/fixtures/seattlerb/parse_line_block.txt
new file mode 100644
index 0000000000..21664649db
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_block.txt
@@ -0,0 +1,2 @@
+a = 42
+p a
diff --git a/test/prism/fixtures/seattlerb/parse_line_block_inline_comment.txt b/test/prism/fixtures/seattlerb/parse_line_block_inline_comment.txt
new file mode 100644
index 0000000000..f55ced714f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_block_inline_comment.txt
@@ -0,0 +1,3 @@
+a
+b # comment
+c
diff --git a/test/prism/fixtures/seattlerb/parse_line_block_inline_comment_leading_newlines.txt b/test/prism/fixtures/seattlerb/parse_line_block_inline_comment_leading_newlines.txt
new file mode 100644
index 0000000000..6f1fee62a0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_block_inline_comment_leading_newlines.txt
@@ -0,0 +1,7 @@
+
+
+
+a
+b # comment
+# another comment
+c
diff --git a/test/prism/fixtures/seattlerb/parse_line_block_inline_multiline_comment.txt b/test/prism/fixtures/seattlerb/parse_line_block_inline_multiline_comment.txt
new file mode 100644
index 0000000000..b00de34dc0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_block_inline_multiline_comment.txt
@@ -0,0 +1,4 @@
+a
+b # comment
+# another comment
+c
diff --git a/test/prism/fixtures/seattlerb/parse_line_call_ivar_arg_no_parens_line_break.txt b/test/prism/fixtures/seattlerb/parse_line_call_ivar_arg_no_parens_line_break.txt
new file mode 100644
index 0000000000..73785eb794
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_call_ivar_arg_no_parens_line_break.txt
@@ -0,0 +1,2 @@
+a @b
+
diff --git a/test/prism/fixtures/seattlerb/parse_line_call_ivar_line_break_paren.txt b/test/prism/fixtures/seattlerb/parse_line_call_ivar_line_break_paren.txt
new file mode 100644
index 0000000000..6f136e6d6f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_call_ivar_line_break_paren.txt
@@ -0,0 +1,2 @@
+a(@b
+)
diff --git a/test/prism/fixtures/seattlerb/parse_line_call_no_args.txt b/test/prism/fixtures/seattlerb/parse_line_call_no_args.txt
new file mode 100644
index 0000000000..7900afd4b8
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_call_no_args.txt
@@ -0,0 +1,3 @@
+f do |x, y|
+ x + y
+end
diff --git a/test/prism/fixtures/seattlerb/parse_line_defn_complex.txt b/test/prism/fixtures/seattlerb/parse_line_defn_complex.txt
new file mode 100644
index 0000000000..244a8e862b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_defn_complex.txt
@@ -0,0 +1,5 @@
+def x(y)
+ p(y)
+ y *= 2
+ return y;
+end
diff --git a/test/prism/fixtures/seattlerb/parse_line_defn_no_parens.txt b/test/prism/fixtures/seattlerb/parse_line_defn_no_parens.txt
new file mode 100644
index 0000000000..373ca7fbec
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_defn_no_parens.txt
@@ -0,0 +1,6 @@
+def f
+
+end
+
+def f
+end
diff --git a/test/prism/fixtures/seattlerb/parse_line_defn_no_parens_args.txt b/test/prism/fixtures/seattlerb/parse_line_defn_no_parens_args.txt
new file mode 100644
index 0000000000..10f004a149
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_defn_no_parens_args.txt
@@ -0,0 +1,2 @@
+def f a
+end
diff --git a/test/prism/fixtures/seattlerb/parse_line_dot2.txt b/test/prism/fixtures/seattlerb/parse_line_dot2.txt
new file mode 100644
index 0000000000..61c7554221
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_dot2.txt
@@ -0,0 +1,5 @@
+0..
+4
+a..
+b
+c
diff --git a/test/prism/fixtures/seattlerb/parse_line_dot2_open.txt b/test/prism/fixtures/seattlerb/parse_line_dot2_open.txt
new file mode 100644
index 0000000000..b3e1e5aaf9
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_dot2_open.txt
@@ -0,0 +1,3 @@
+0..
+; a..
+; c
diff --git a/test/prism/fixtures/seattlerb/parse_line_dot3.txt b/test/prism/fixtures/seattlerb/parse_line_dot3.txt
new file mode 100644
index 0000000000..d1866b41de
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_dot3.txt
@@ -0,0 +1,5 @@
+0...
+4
+a...
+b
+c
diff --git a/test/prism/fixtures/seattlerb/parse_line_dot3_open.txt b/test/prism/fixtures/seattlerb/parse_line_dot3_open.txt
new file mode 100644
index 0000000000..38e7634b21
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_dot3_open.txt
@@ -0,0 +1,3 @@
+0...
+; a...
+; c
diff --git a/test/prism/fixtures/seattlerb/parse_line_dstr_escaped_newline.txt b/test/prism/fixtures/seattlerb/parse_line_dstr_escaped_newline.txt
new file mode 100644
index 0000000000..29c1754915
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_dstr_escaped_newline.txt
@@ -0,0 +1,3 @@
+"a\n#{
+}"
+true
diff --git a/test/prism/fixtures/seattlerb/parse_line_dstr_soft_newline.txt b/test/prism/fixtures/seattlerb/parse_line_dstr_soft_newline.txt
new file mode 100644
index 0000000000..e4dbd7bcb2
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_dstr_soft_newline.txt
@@ -0,0 +1,4 @@
+"a
+#{
+}"
+true
diff --git a/test/prism/fixtures/seattlerb/parse_line_evstr_after_break.txt b/test/prism/fixtures/seattlerb/parse_line_evstr_after_break.txt
new file mode 100644
index 0000000000..c1d91a51c4
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_evstr_after_break.txt
@@ -0,0 +1,2 @@
+"a"\
+"#{b}"
diff --git a/test/prism/fixtures/seattlerb/parse_line_hash_lit.txt b/test/prism/fixtures/seattlerb/parse_line_hash_lit.txt
new file mode 100644
index 0000000000..25f8c90a06
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_hash_lit.txt
@@ -0,0 +1,3 @@
+{
+:s1 => 1,
+}
diff --git a/test/prism/fixtures/seattlerb/parse_line_heredoc.txt b/test/prism/fixtures/seattlerb/parse_line_heredoc.txt
new file mode 100644
index 0000000000..201339534c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_heredoc.txt
@@ -0,0 +1,5 @@
+ string = <<-HEREDOC.strip
+ very long string
+ HEREDOC
+ puts string
+
diff --git a/test/prism/fixtures/seattlerb/parse_line_heredoc_evstr.txt b/test/prism/fixtures/seattlerb/parse_line_heredoc_evstr.txt
new file mode 100644
index 0000000000..d50844db4b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_heredoc_evstr.txt
@@ -0,0 +1,4 @@
+<<-A
+a
+#{b}
+A
diff --git a/test/prism/fixtures/seattlerb/parse_line_heredoc_hardnewline.txt b/test/prism/fixtures/seattlerb/parse_line_heredoc_hardnewline.txt
new file mode 100644
index 0000000000..3fbf0f2c26
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_heredoc_hardnewline.txt
@@ -0,0 +1,7 @@
+<<-EOFOO
+\n\n\n\n\n\n\n\n\n
+EOFOO
+
+class Foo
+end
+
diff --git a/test/prism/fixtures/seattlerb/parse_line_heredoc_regexp_chars.txt b/test/prism/fixtures/seattlerb/parse_line_heredoc_regexp_chars.txt
new file mode 100644
index 0000000000..5dab9cf4e7
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_heredoc_regexp_chars.txt
@@ -0,0 +1,5 @@
+ string = <<-"^D"
+ very long string
+ ^D
+ puts string
+
diff --git a/test/prism/fixtures/seattlerb/parse_line_iter_call_no_parens.txt b/test/prism/fixtures/seattlerb/parse_line_iter_call_no_parens.txt
new file mode 100644
index 0000000000..bf1b33c8a2
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_iter_call_no_parens.txt
@@ -0,0 +1,3 @@
+f a do |x, y|
+ x + y
+end
diff --git a/test/prism/fixtures/seattlerb/parse_line_iter_call_parens.txt b/test/prism/fixtures/seattlerb/parse_line_iter_call_parens.txt
new file mode 100644
index 0000000000..25e9ea1c67
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_iter_call_parens.txt
@@ -0,0 +1,3 @@
+f(a) do |x, y|
+ x + y
+end
diff --git a/test/prism/fixtures/seattlerb/parse_line_multiline_str.txt b/test/prism/fixtures/seattlerb/parse_line_multiline_str.txt
new file mode 100644
index 0000000000..cdefb3c9b7
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_multiline_str.txt
@@ -0,0 +1,3 @@
+"a
+b"
+1
diff --git a/test/prism/fixtures/seattlerb/parse_line_multiline_str_literal_n.txt b/test/prism/fixtures/seattlerb/parse_line_multiline_str_literal_n.txt
new file mode 100644
index 0000000000..a179ba8c9c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_multiline_str_literal_n.txt
@@ -0,0 +1,2 @@
+"a\nb"
+1
diff --git a/test/prism/fixtures/seattlerb/parse_line_newlines.txt b/test/prism/fixtures/seattlerb/parse_line_newlines.txt
new file mode 100644
index 0000000000..28b0c286e8
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_newlines.txt
@@ -0,0 +1,3 @@
+true
+
+
diff --git a/test/prism/fixtures/seattlerb/parse_line_op_asgn.txt b/test/prism/fixtures/seattlerb/parse_line_op_asgn.txt
new file mode 100644
index 0000000000..f2691c2ce4
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_op_asgn.txt
@@ -0,0 +1,4 @@
+ foo +=
+ bar
+ baz
+
diff --git a/test/prism/fixtures/seattlerb/parse_line_postexe.txt b/test/prism/fixtures/seattlerb/parse_line_postexe.txt
new file mode 100644
index 0000000000..fd8b318d19
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_postexe.txt
@@ -0,0 +1,3 @@
+END {
+foo
+}
diff --git a/test/prism/fixtures/seattlerb/parse_line_preexe.txt b/test/prism/fixtures/seattlerb/parse_line_preexe.txt
new file mode 100644
index 0000000000..b3eda77ebc
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_preexe.txt
@@ -0,0 +1,3 @@
+BEGIN {
+foo
+}
diff --git a/test/prism/fixtures/seattlerb/parse_line_rescue.txt b/test/prism/fixtures/seattlerb/parse_line_rescue.txt
new file mode 100644
index 0000000000..a583160ce2
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_rescue.txt
@@ -0,0 +1,8 @@
+begin
+ a
+rescue
+ b
+rescue
+ c
+end
+
diff --git a/test/prism/fixtures/seattlerb/parse_line_return.txt b/test/prism/fixtures/seattlerb/parse_line_return.txt
new file mode 100644
index 0000000000..81021c2644
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_return.txt
@@ -0,0 +1,6 @@
+ def blah
+ if true then
+ return 42
+ end
+ end
+
diff --git a/test/prism/fixtures/seattlerb/parse_line_str_with_newline_escape.txt b/test/prism/fixtures/seattlerb/parse_line_str_with_newline_escape.txt
new file mode 100644
index 0000000000..b2b6bb8234
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_str_with_newline_escape.txt
@@ -0,0 +1 @@
+a("\n", true)
diff --git a/test/prism/fixtures/seattlerb/parse_line_to_ary.txt b/test/prism/fixtures/seattlerb/parse_line_to_ary.txt
new file mode 100644
index 0000000000..590d0abd14
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_to_ary.txt
@@ -0,0 +1,3 @@
+a,
+b = c
+d
diff --git a/test/prism/fixtures/seattlerb/parse_line_trailing_newlines.txt b/test/prism/fixtures/seattlerb/parse_line_trailing_newlines.txt
new file mode 100644
index 0000000000..afa826fb50
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_line_trailing_newlines.txt
@@ -0,0 +1,2 @@
+a
+b
diff --git a/test/prism/fixtures/seattlerb/parse_opt_call_args_assocs_comma.txt b/test/prism/fixtures/seattlerb/parse_opt_call_args_assocs_comma.txt
new file mode 100644
index 0000000000..649c109ea1
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_opt_call_args_assocs_comma.txt
@@ -0,0 +1 @@
+1[2=>3,]
diff --git a/test/prism/fixtures/seattlerb/parse_opt_call_args_lit_comma.txt b/test/prism/fixtures/seattlerb/parse_opt_call_args_lit_comma.txt
new file mode 100644
index 0000000000..741cd4ffd1
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_opt_call_args_lit_comma.txt
@@ -0,0 +1 @@
+1[2,]
diff --git a/test/prism/fixtures/seattlerb/parse_pattern_019.txt b/test/prism/fixtures/seattlerb/parse_pattern_019.txt
new file mode 100644
index 0000000000..1e8a75902d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_pattern_019.txt
@@ -0,0 +1,5 @@
+case 0
+in -1..1
+ true
+end
+
diff --git a/test/prism/fixtures/seattlerb/parse_pattern_044.txt b/test/prism/fixtures/seattlerb/parse_pattern_044.txt
new file mode 100644
index 0000000000..a6a0ac6c1c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_pattern_044.txt
@@ -0,0 +1,5 @@
+case obj
+in Object[]
+ true
+end
+
diff --git a/test/prism/fixtures/seattlerb/parse_pattern_051.txt b/test/prism/fixtures/seattlerb/parse_pattern_051.txt
new file mode 100644
index 0000000000..b7cf769f50
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_pattern_051.txt
@@ -0,0 +1,5 @@
+case [0, 1, 2]
+in [0, 1,]
+ true
+end
+
diff --git a/test/prism/fixtures/seattlerb/parse_pattern_058.txt b/test/prism/fixtures/seattlerb/parse_pattern_058.txt
new file mode 100644
index 0000000000..bd7537098e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_pattern_058.txt
@@ -0,0 +1,5 @@
+case {a: 0}
+in {a:, **rest}
+ [a, rest]
+end
+
diff --git a/test/prism/fixtures/seattlerb/parse_pattern_058_2.txt b/test/prism/fixtures/seattlerb/parse_pattern_058_2.txt
new file mode 100644
index 0000000000..eb1b3cd8ab
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_pattern_058_2.txt
@@ -0,0 +1,5 @@
+case {a: 0}
+in {a:, **}
+ [a]
+end
+
diff --git a/test/prism/fixtures/seattlerb/parse_pattern_069.txt b/test/prism/fixtures/seattlerb/parse_pattern_069.txt
new file mode 100644
index 0000000000..f43dff8959
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_pattern_069.txt
@@ -0,0 +1,5 @@
+case :a
+in Object[b: 1]
+ 1
+end
+
diff --git a/test/prism/fixtures/seattlerb/parse_pattern_076.txt b/test/prism/fixtures/seattlerb/parse_pattern_076.txt
new file mode 100644
index 0000000000..bb947605b3
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_pattern_076.txt
@@ -0,0 +1,5 @@
+case {a: 1}
+in {a: 1, **nil}
+ true
+end
+
diff --git a/test/prism/fixtures/seattlerb/parse_until_not_canonical.txt b/test/prism/fixtures/seattlerb/parse_until_not_canonical.txt
new file mode 100644
index 0000000000..4de38968dc
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_until_not_canonical.txt
@@ -0,0 +1,3 @@
+until not var.nil?
+ 'foo'
+end
diff --git a/test/prism/fixtures/seattlerb/parse_until_not_noncanonical.txt b/test/prism/fixtures/seattlerb/parse_until_not_noncanonical.txt
new file mode 100644
index 0000000000..4de38968dc
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_until_not_noncanonical.txt
@@ -0,0 +1,3 @@
+until not var.nil?
+ 'foo'
+end
diff --git a/test/prism/fixtures/seattlerb/parse_while_not_canonical.txt b/test/prism/fixtures/seattlerb/parse_while_not_canonical.txt
new file mode 100644
index 0000000000..5aa464167f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_while_not_canonical.txt
@@ -0,0 +1,3 @@
+while not var.nil?
+ 'foo'
+end
diff --git a/test/prism/fixtures/seattlerb/parse_while_not_noncanonical.txt b/test/prism/fixtures/seattlerb/parse_while_not_noncanonical.txt
new file mode 100644
index 0000000000..5aa464167f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/parse_while_not_noncanonical.txt
@@ -0,0 +1,3 @@
+while not var.nil?
+ 'foo'
+end
diff --git a/test/prism/fixtures/seattlerb/pctW_lineno.txt b/test/prism/fixtures/seattlerb/pctW_lineno.txt
new file mode 100644
index 0000000000..b222ff0174
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/pctW_lineno.txt
@@ -0,0 +1,5 @@
+%W(a\nb
+c d
+e\
+f
+gy h\y i\y)
diff --git a/test/prism/fixtures/seattlerb/pct_Q_backslash_nl.txt b/test/prism/fixtures/seattlerb/pct_Q_backslash_nl.txt
new file mode 100644
index 0000000000..4420560d2b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/pct_Q_backslash_nl.txt
@@ -0,0 +1,2 @@
+%q{ \
+}
diff --git a/test/prism/fixtures/seattlerb/pct_nl.txt b/test/prism/fixtures/seattlerb/pct_nl.txt
new file mode 100644
index 0000000000..2cee1cdd44
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/pct_nl.txt
@@ -0,0 +1,3 @@
+x = %
+
+
diff --git a/test/prism/fixtures/seattlerb/pct_w_heredoc_interp_nested.txt b/test/prism/fixtures/seattlerb/pct_w_heredoc_interp_nested.txt
new file mode 100644
index 0000000000..4e084661bf
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/pct_w_heredoc_interp_nested.txt
@@ -0,0 +1,4 @@
+%W( 1 #{<<A} 3
+2
+A
+ 4 5 )
diff --git a/test/prism/fixtures/seattlerb/pipe_semicolon.txt b/test/prism/fixtures/seattlerb/pipe_semicolon.txt
new file mode 100644
index 0000000000..e692cc434f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/pipe_semicolon.txt
@@ -0,0 +1 @@
+a.b do | ; c | end
diff --git a/test/prism/fixtures/seattlerb/pipe_space.txt b/test/prism/fixtures/seattlerb/pipe_space.txt
new file mode 100644
index 0000000000..7f0df799b9
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/pipe_space.txt
@@ -0,0 +1 @@
+a.b do | | end
diff --git a/test/prism/fixtures/seattlerb/qWords_space.txt b/test/prism/fixtures/seattlerb/qWords_space.txt
new file mode 100644
index 0000000000..a8299ba3f8
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/qWords_space.txt
@@ -0,0 +1 @@
+%W( )
diff --git a/test/prism/fixtures/seattlerb/qsymbols.txt b/test/prism/fixtures/seattlerb/qsymbols.txt
new file mode 100644
index 0000000000..cb9ff09ae0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/qsymbols.txt
@@ -0,0 +1 @@
+%I(a b c)
diff --git a/test/prism/fixtures/seattlerb/qsymbols_empty.txt b/test/prism/fixtures/seattlerb/qsymbols_empty.txt
new file mode 100644
index 0000000000..10a3279907
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/qsymbols_empty.txt
@@ -0,0 +1 @@
+%I()
diff --git a/test/prism/fixtures/seattlerb/qsymbols_empty_space.txt b/test/prism/fixtures/seattlerb/qsymbols_empty_space.txt
new file mode 100644
index 0000000000..819f16ad06
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/qsymbols_empty_space.txt
@@ -0,0 +1 @@
+%I( )
diff --git a/test/prism/fixtures/seattlerb/qsymbols_interp.txt b/test/prism/fixtures/seattlerb/qsymbols_interp.txt
new file mode 100644
index 0000000000..2f34883867
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/qsymbols_interp.txt
@@ -0,0 +1 @@
+%I(a b#{1+1} c)
diff --git a/test/prism/fixtures/seattlerb/quoted_symbol_hash_arg.txt b/test/prism/fixtures/seattlerb/quoted_symbol_hash_arg.txt
new file mode 100644
index 0000000000..4f1295ef18
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/quoted_symbol_hash_arg.txt
@@ -0,0 +1 @@
+puts 'a': {}
diff --git a/test/prism/fixtures/seattlerb/quoted_symbol_keys.txt b/test/prism/fixtures/seattlerb/quoted_symbol_keys.txt
new file mode 100644
index 0000000000..c6a946723d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/quoted_symbol_keys.txt
@@ -0,0 +1 @@
+{ 'a': :b }
diff --git a/test/prism/fixtures/seattlerb/qw_escape.txt b/test/prism/fixtures/seattlerb/qw_escape.txt
new file mode 100644
index 0000000000..a94a0e5dcb
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/qw_escape.txt
@@ -0,0 +1 @@
+%q(\')
diff --git a/test/prism/fixtures/seattlerb/qw_escape_term.txt b/test/prism/fixtures/seattlerb/qw_escape_term.txt
new file mode 100644
index 0000000000..9734fc3421
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/qw_escape_term.txt
@@ -0,0 +1 @@
+%q|blah blah \| blah blah|
diff --git a/test/prism/fixtures/seattlerb/qwords_empty.txt b/test/prism/fixtures/seattlerb/qwords_empty.txt
new file mode 100644
index 0000000000..69cc6679d6
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/qwords_empty.txt
@@ -0,0 +1 @@
+%w()
diff --git a/test/prism/fixtures/seattlerb/read_escape_unicode_curlies.txt b/test/prism/fixtures/seattlerb/read_escape_unicode_curlies.txt
new file mode 100644
index 0000000000..427b94cc4d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/read_escape_unicode_curlies.txt
@@ -0,0 +1 @@
+?\u{00a0}
diff --git a/test/prism/fixtures/seattlerb/read_escape_unicode_h4.txt b/test/prism/fixtures/seattlerb/read_escape_unicode_h4.txt
new file mode 100644
index 0000000000..71aa7a4347
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/read_escape_unicode_h4.txt
@@ -0,0 +1 @@
+?\u00a0
diff --git a/test/prism/fixtures/seattlerb/regexp.txt b/test/prism/fixtures/seattlerb/regexp.txt
new file mode 100644
index 0000000000..bc06458c5c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/regexp.txt
@@ -0,0 +1,9 @@
+/wtf/
+
+/wtf/m
+
+/wtf/n
+
+/wtf/nm
+
+/wtf/nmnmnmnm
diff --git a/test/prism/fixtures/seattlerb/regexp_esc_C_slash.txt b/test/prism/fixtures/seattlerb/regexp_esc_C_slash.txt
new file mode 100644
index 0000000000..1fd9207c66
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/regexp_esc_C_slash.txt
@@ -0,0 +1 @@
+/\cC\d/
diff --git a/test/prism/fixtures/seattlerb/regexp_esc_u.txt b/test/prism/fixtures/seattlerb/regexp_esc_u.txt
new file mode 100644
index 0000000000..b91704fb0a
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/regexp_esc_u.txt
@@ -0,0 +1 @@
+/[\u0021-\u0027]/
diff --git a/test/prism/fixtures/seattlerb/regexp_escape_extended.txt b/test/prism/fixtures/seattlerb/regexp_escape_extended.txt
new file mode 100644
index 0000000000..73dcbab69c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/regexp_escape_extended.txt
@@ -0,0 +1 @@
+/\“/
diff --git a/test/prism/fixtures/seattlerb/regexp_unicode_curlies.txt b/test/prism/fixtures/seattlerb/regexp_unicode_curlies.txt
new file mode 100644
index 0000000000..5a02bd92ca
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/regexp_unicode_curlies.txt
@@ -0,0 +1,3 @@
+/\u{c0de babe}/
+
+/\u{df}/
diff --git a/test/prism/fixtures/seattlerb/required_kwarg_no_value.txt b/test/prism/fixtures/seattlerb/required_kwarg_no_value.txt
new file mode 100644
index 0000000000..453bcbb33b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/required_kwarg_no_value.txt
@@ -0,0 +1,2 @@
+def x a:, b:
+end
diff --git a/test/prism/fixtures/seattlerb/rescue_do_end_ensure_result.txt b/test/prism/fixtures/seattlerb/rescue_do_end_ensure_result.txt
new file mode 100644
index 0000000000..7049be66c5
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/rescue_do_end_ensure_result.txt
@@ -0,0 +1,5 @@
+proc do
+ :begin
+ensure
+ :ensure
+end.call
diff --git a/test/prism/fixtures/seattlerb/rescue_do_end_no_raise.txt b/test/prism/fixtures/seattlerb/rescue_do_end_no_raise.txt
new file mode 100644
index 0000000000..5f16ec2f15
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/rescue_do_end_no_raise.txt
@@ -0,0 +1,9 @@
+tap do
+ :begin
+rescue
+ :rescue
+else
+ :else
+ensure
+ :ensure
+end
diff --git a/test/prism/fixtures/seattlerb/rescue_do_end_raised.txt b/test/prism/fixtures/seattlerb/rescue_do_end_raised.txt
new file mode 100644
index 0000000000..d04215eb48
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/rescue_do_end_raised.txt
@@ -0,0 +1,5 @@
+tap do
+ raise
+ensure
+ :ensure
+end
diff --git a/test/prism/fixtures/seattlerb/rescue_do_end_rescued.txt b/test/prism/fixtures/seattlerb/rescue_do_end_rescued.txt
new file mode 100644
index 0000000000..4b377511f0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/rescue_do_end_rescued.txt
@@ -0,0 +1,9 @@
+tap do
+ raise
+rescue
+ :rescue
+else
+ :else
+ensure
+ :ensure
+end
diff --git a/test/prism/fixtures/seattlerb/rescue_in_block.txt b/test/prism/fixtures/seattlerb/rescue_in_block.txt
new file mode 100644
index 0000000000..c6e834aa1e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/rescue_in_block.txt
@@ -0,0 +1,4 @@
+blah do
+rescue
+ stuff
+end
diff --git a/test/prism/fixtures/seattlerb/rescue_parens.txt b/test/prism/fixtures/seattlerb/rescue_parens.txt
new file mode 100644
index 0000000000..f0eb4db417
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/rescue_parens.txt
@@ -0,0 +1 @@
+a (b rescue c)
diff --git a/test/prism/fixtures/seattlerb/return_call_assocs.txt b/test/prism/fixtures/seattlerb/return_call_assocs.txt
new file mode 100644
index 0000000000..34ea778f17
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/return_call_assocs.txt
@@ -0,0 +1,11 @@
+return 1, :z => 1
+
+return 1, :z => 1, :w => 2
+
+return y :z=>1
+
+return y z:1
+
+return y(z:1)
+
+return y(z=>1)
diff --git a/test/prism/fixtures/seattlerb/rhs_asgn.txt b/test/prism/fixtures/seattlerb/rhs_asgn.txt
new file mode 100644
index 0000000000..ca581031e2
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/rhs_asgn.txt
@@ -0,0 +1 @@
+42 => n
diff --git a/test/prism/fixtures/seattlerb/ruby21_numbers.txt b/test/prism/fixtures/seattlerb/ruby21_numbers.txt
new file mode 100644
index 0000000000..34ceb63a0c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/ruby21_numbers.txt
@@ -0,0 +1 @@
+[1i, 2r, 3ri]
diff --git a/test/prism/fixtures/seattlerb/safe_attrasgn.txt b/test/prism/fixtures/seattlerb/safe_attrasgn.txt
new file mode 100644
index 0000000000..1279e02cfc
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/safe_attrasgn.txt
@@ -0,0 +1 @@
+a&.b = 1
diff --git a/test/prism/fixtures/seattlerb/safe_attrasgn_constant.txt b/test/prism/fixtures/seattlerb/safe_attrasgn_constant.txt
new file mode 100644
index 0000000000..3a17ac6bcf
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/safe_attrasgn_constant.txt
@@ -0,0 +1 @@
+a&.B = 1
diff --git a/test/prism/fixtures/seattlerb/safe_call.txt b/test/prism/fixtures/seattlerb/safe_call.txt
new file mode 100644
index 0000000000..8ecd27e0fe
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/safe_call.txt
@@ -0,0 +1 @@
+a&.b
diff --git a/test/prism/fixtures/seattlerb/safe_call_after_newline.txt b/test/prism/fixtures/seattlerb/safe_call_after_newline.txt
new file mode 100644
index 0000000000..58e3fba554
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/safe_call_after_newline.txt
@@ -0,0 +1,2 @@
+a
+&.b
diff --git a/test/prism/fixtures/seattlerb/safe_call_dot_parens.txt b/test/prism/fixtures/seattlerb/safe_call_dot_parens.txt
new file mode 100644
index 0000000000..5def076640
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/safe_call_dot_parens.txt
@@ -0,0 +1 @@
+a&.()
diff --git a/test/prism/fixtures/seattlerb/safe_call_newline.txt b/test/prism/fixtures/seattlerb/safe_call_newline.txt
new file mode 100644
index 0000000000..8778b46585
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/safe_call_newline.txt
@@ -0,0 +1,2 @@
+a&.b
+
diff --git a/test/prism/fixtures/seattlerb/safe_call_operator.txt b/test/prism/fixtures/seattlerb/safe_call_operator.txt
new file mode 100644
index 0000000000..f3fe2b0392
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/safe_call_operator.txt
@@ -0,0 +1 @@
+a&.> 1
diff --git a/test/prism/fixtures/seattlerb/safe_call_rhs_newline.txt b/test/prism/fixtures/seattlerb/safe_call_rhs_newline.txt
new file mode 100644
index 0000000000..d3b07b77b2
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/safe_call_rhs_newline.txt
@@ -0,0 +1,2 @@
+c = a&.b
+
diff --git a/test/prism/fixtures/seattlerb/safe_calls.txt b/test/prism/fixtures/seattlerb/safe_calls.txt
new file mode 100644
index 0000000000..eafeace500
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/safe_calls.txt
@@ -0,0 +1 @@
+a&.b&.c(1)
diff --git a/test/prism/fixtures/seattlerb/safe_op_asgn.txt b/test/prism/fixtures/seattlerb/safe_op_asgn.txt
new file mode 100644
index 0000000000..8915a1cccf
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/safe_op_asgn.txt
@@ -0,0 +1 @@
+a&.b += x 1
diff --git a/test/prism/fixtures/seattlerb/safe_op_asgn2.txt b/test/prism/fixtures/seattlerb/safe_op_asgn2.txt
new file mode 100644
index 0000000000..0960b2548b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/safe_op_asgn2.txt
@@ -0,0 +1,2 @@
+a&.b ||=
+x;
diff --git a/test/prism/fixtures/seattlerb/slashy_newlines_within_string.txt b/test/prism/fixtures/seattlerb/slashy_newlines_within_string.txt
new file mode 100644
index 0000000000..421989c76f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/slashy_newlines_within_string.txt
@@ -0,0 +1,7 @@
+puts "hello\
+ my\
+ dear\
+ friend"
+
+a + b
+
diff --git a/test/prism/fixtures/seattlerb/stabby_arg_no_paren.txt b/test/prism/fixtures/seattlerb/stabby_arg_no_paren.txt
new file mode 100644
index 0000000000..f16bed4ccf
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/stabby_arg_no_paren.txt
@@ -0,0 +1 @@
+->a{}
diff --git a/test/prism/fixtures/seattlerb/stabby_arg_opt_splat_arg_block_omfg.txt b/test/prism/fixtures/seattlerb/stabby_arg_opt_splat_arg_block_omfg.txt
new file mode 100644
index 0000000000..87a7c5dad3
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/stabby_arg_opt_splat_arg_block_omfg.txt
@@ -0,0 +1 @@
+->(b, c=1, *d, e, &f){}
diff --git a/test/prism/fixtures/seattlerb/stabby_block_iter_call.txt b/test/prism/fixtures/seattlerb/stabby_block_iter_call.txt
new file mode 100644
index 0000000000..5e9e3f5527
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/stabby_block_iter_call.txt
@@ -0,0 +1,4 @@
+x -> () do
+a.b do
+end
+end
diff --git a/test/prism/fixtures/seattlerb/stabby_block_iter_call_no_target_with_arg.txt b/test/prism/fixtures/seattlerb/stabby_block_iter_call_no_target_with_arg.txt
new file mode 100644
index 0000000000..7235394751
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/stabby_block_iter_call_no_target_with_arg.txt
@@ -0,0 +1,4 @@
+x -> () do
+a(1) do
+end
+end
diff --git a/test/prism/fixtures/seattlerb/stabby_block_kw.txt b/test/prism/fixtures/seattlerb/stabby_block_kw.txt
new file mode 100644
index 0000000000..74d9e0a328
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/stabby_block_kw.txt
@@ -0,0 +1 @@
+-> (k:42) { }
diff --git a/test/prism/fixtures/seattlerb/stabby_block_kw__required.txt b/test/prism/fixtures/seattlerb/stabby_block_kw__required.txt
new file mode 100644
index 0000000000..bd16ffa73c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/stabby_block_kw__required.txt
@@ -0,0 +1 @@
+-> (k:) { }
diff --git a/test/prism/fixtures/seattlerb/stabby_proc_scope.txt b/test/prism/fixtures/seattlerb/stabby_proc_scope.txt
new file mode 100644
index 0000000000..1f7f9ff52b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/stabby_proc_scope.txt
@@ -0,0 +1 @@
+->(a; b) {}
diff --git a/test/prism/fixtures/seattlerb/str_backslashes.txt b/test/prism/fixtures/seattlerb/str_backslashes.txt
new file mode 100644
index 0000000000..5fd6da361b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_backslashes.txt
@@ -0,0 +1 @@
+x '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'
diff --git a/test/prism/fixtures/seattlerb/str_double_double_escaped_newline.txt b/test/prism/fixtures/seattlerb/str_double_double_escaped_newline.txt
new file mode 100644
index 0000000000..2b022a55f6
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_double_double_escaped_newline.txt
@@ -0,0 +1 @@
+a "\\n";b
diff --git a/test/prism/fixtures/seattlerb/str_double_escaped_newline.txt b/test/prism/fixtures/seattlerb/str_double_escaped_newline.txt
new file mode 100644
index 0000000000..e439225344
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_double_escaped_newline.txt
@@ -0,0 +1 @@
+a "\n";b
diff --git a/test/prism/fixtures/seattlerb/str_double_newline.txt b/test/prism/fixtures/seattlerb/str_double_newline.txt
new file mode 100644
index 0000000000..2d439506ca
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_double_newline.txt
@@ -0,0 +1,2 @@
+a "
+";b
diff --git a/test/prism/fixtures/seattlerb/str_evstr.txt b/test/prism/fixtures/seattlerb/str_evstr.txt
new file mode 100644
index 0000000000..86c6d1526d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_evstr.txt
@@ -0,0 +1 @@
+"a #{b}"
diff --git a/test/prism/fixtures/seattlerb/str_evstr_escape.txt b/test/prism/fixtures/seattlerb/str_evstr_escape.txt
new file mode 100644
index 0000000000..517dfd4778
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_evstr_escape.txt
@@ -0,0 +1 @@
+"a #{b}\302\275"
diff --git a/test/prism/fixtures/seattlerb/str_heredoc_interp.txt b/test/prism/fixtures/seattlerb/str_heredoc_interp.txt
new file mode 100644
index 0000000000..aa2613008c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_heredoc_interp.txt
@@ -0,0 +1,5 @@
+<<""
+#{x}
+blah2
+
+
diff --git a/test/prism/fixtures/seattlerb/str_interp_ternary_or_label.txt b/test/prism/fixtures/seattlerb/str_interp_ternary_or_label.txt
new file mode 100644
index 0000000000..fe6637678f
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_interp_ternary_or_label.txt
@@ -0,0 +1 @@
+"#{a.b? ? ""+a+"": ""}"
diff --git a/test/prism/fixtures/seattlerb/str_lit_concat_bad_encodings.txt b/test/prism/fixtures/seattlerb/str_lit_concat_bad_encodings.txt
new file mode 100644
index 0000000000..f4eb3971bb
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_lit_concat_bad_encodings.txt
@@ -0,0 +1,2 @@
+"\xE3\xD3\x8B\xE3\x83\xBC\x83\xE3\x83\xE3\x82\xB3\xA3\x82\x99" \
+ "\xE3\x83\xB3\xE3\x83\x8F\xE3\x82\x9A\xC3\xBD;foo@bar.com"
diff --git a/test/prism/fixtures/seattlerb/str_newline_hash_line_number.txt b/test/prism/fixtures/seattlerb/str_newline_hash_line_number.txt
new file mode 100644
index 0000000000..9c8f702000
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_newline_hash_line_number.txt
@@ -0,0 +1,2 @@
+"\n\n\n\n#"
+1
diff --git a/test/prism/fixtures/seattlerb/str_pct_Q_nested.txt b/test/prism/fixtures/seattlerb/str_pct_Q_nested.txt
new file mode 100644
index 0000000000..1f3d0613e5
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_pct_Q_nested.txt
@@ -0,0 +1 @@
+%Q[before [#{nest}] after]
diff --git a/test/prism/fixtures/seattlerb/str_pct_nested_nested.txt b/test/prism/fixtures/seattlerb/str_pct_nested_nested.txt
new file mode 100644
index 0000000000..cb12415215
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_pct_nested_nested.txt
@@ -0,0 +1 @@
+%{ { #{ "#{1}" } } }
diff --git a/test/prism/fixtures/seattlerb/str_pct_q.txt b/test/prism/fixtures/seattlerb/str_pct_q.txt
new file mode 100644
index 0000000000..65d71197c9
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_pct_q.txt
@@ -0,0 +1 @@
+%q{a b c}
diff --git a/test/prism/fixtures/seattlerb/str_single_double_escaped_newline.txt b/test/prism/fixtures/seattlerb/str_single_double_escaped_newline.txt
new file mode 100644
index 0000000000..2ff0aec111
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_single_double_escaped_newline.txt
@@ -0,0 +1 @@
+a '\\n';b
diff --git a/test/prism/fixtures/seattlerb/str_single_escaped_newline.txt b/test/prism/fixtures/seattlerb/str_single_escaped_newline.txt
new file mode 100644
index 0000000000..5abb8d6334
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_single_escaped_newline.txt
@@ -0,0 +1 @@
+a '\n';b
diff --git a/test/prism/fixtures/seattlerb/str_single_newline.txt b/test/prism/fixtures/seattlerb/str_single_newline.txt
new file mode 100644
index 0000000000..1033cc7e96
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_single_newline.txt
@@ -0,0 +1,2 @@
+a '
+';b
diff --git a/test/prism/fixtures/seattlerb/str_str.txt b/test/prism/fixtures/seattlerb/str_str.txt
new file mode 100644
index 0000000000..388d777dc2
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_str.txt
@@ -0,0 +1 @@
+"a #{'b'}"
diff --git a/test/prism/fixtures/seattlerb/str_str_str.txt b/test/prism/fixtures/seattlerb/str_str_str.txt
new file mode 100644
index 0000000000..d64e01dc5d
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/str_str_str.txt
@@ -0,0 +1 @@
+"a #{'b'} c"
diff --git a/test/prism/fixtures/seattlerb/super_arg.txt b/test/prism/fixtures/seattlerb/super_arg.txt
new file mode 100644
index 0000000000..1b19ecd51c
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/super_arg.txt
@@ -0,0 +1 @@
+super 42
diff --git a/test/prism/fixtures/seattlerb/symbol_empty.txt b/test/prism/fixtures/seattlerb/symbol_empty.txt
new file mode 100644
index 0000000000..cbb260bb4e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/symbol_empty.txt
@@ -0,0 +1 @@
+:''
diff --git a/test/prism/fixtures/seattlerb/symbol_list.txt b/test/prism/fixtures/seattlerb/symbol_list.txt
new file mode 100644
index 0000000000..d357195184
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/symbol_list.txt
@@ -0,0 +1 @@
+%I[#{a} #{b}]
diff --git a/test/prism/fixtures/seattlerb/symbols.txt b/test/prism/fixtures/seattlerb/symbols.txt
new file mode 100644
index 0000000000..3ec930ce66
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/symbols.txt
@@ -0,0 +1 @@
+%i(a b c)
diff --git a/test/prism/fixtures/seattlerb/symbols_empty.txt b/test/prism/fixtures/seattlerb/symbols_empty.txt
new file mode 100644
index 0000000000..840948efb2
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/symbols_empty.txt
@@ -0,0 +1 @@
+%i()
diff --git a/test/prism/fixtures/seattlerb/symbols_empty_space.txt b/test/prism/fixtures/seattlerb/symbols_empty_space.txt
new file mode 100644
index 0000000000..16c2e68a2b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/symbols_empty_space.txt
@@ -0,0 +1 @@
+%i( )
diff --git a/test/prism/fixtures/seattlerb/symbols_interp.txt b/test/prism/fixtures/seattlerb/symbols_interp.txt
new file mode 100644
index 0000000000..63116eb632
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/symbols_interp.txt
@@ -0,0 +1 @@
+%i(a b#{1+1} c)
diff --git a/test/prism/fixtures/seattlerb/thingy.txt b/test/prism/fixtures/seattlerb/thingy.txt
new file mode 100644
index 0000000000..5aa598c4be
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/thingy.txt
@@ -0,0 +1,3 @@
+f.(42)
+
+f::(42)
diff --git a/test/prism/fixtures/seattlerb/uminus_float.txt b/test/prism/fixtures/seattlerb/uminus_float.txt
new file mode 100644
index 0000000000..1344bfd9db
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/uminus_float.txt
@@ -0,0 +1 @@
+-0.0
diff --git a/test/prism/fixtures/seattlerb/unary_minus.txt b/test/prism/fixtures/seattlerb/unary_minus.txt
new file mode 100644
index 0000000000..66af866f85
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/unary_minus.txt
@@ -0,0 +1 @@
+-a
diff --git a/test/prism/fixtures/seattlerb/unary_plus.txt b/test/prism/fixtures/seattlerb/unary_plus.txt
new file mode 100644
index 0000000000..daea40b71e
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/unary_plus.txt
@@ -0,0 +1 @@
++a
diff --git a/test/prism/fixtures/seattlerb/unary_plus_on_literal.txt b/test/prism/fixtures/seattlerb/unary_plus_on_literal.txt
new file mode 100644
index 0000000000..752331df47
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/unary_plus_on_literal.txt
@@ -0,0 +1 @@
++:a
diff --git a/test/prism/fixtures/seattlerb/unary_tilde.txt b/test/prism/fixtures/seattlerb/unary_tilde.txt
new file mode 100644
index 0000000000..f0a507b437
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/unary_tilde.txt
@@ -0,0 +1 @@
+~a
diff --git a/test/prism/fixtures/seattlerb/utf8_bom.txt b/test/prism/fixtures/seattlerb/utf8_bom.txt
new file mode 100644
index 0000000000..c8e9e1cbae
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/utf8_bom.txt
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby -w
+p 0
+
diff --git a/test/prism/fixtures/seattlerb/when_splat.txt b/test/prism/fixtures/seattlerb/when_splat.txt
new file mode 100644
index 0000000000..6b79f5dad0
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/when_splat.txt
@@ -0,0 +1 @@
+case a; when *b then; end
diff --git a/test/prism/fixtures/seattlerb/words_interp.txt b/test/prism/fixtures/seattlerb/words_interp.txt
new file mode 100644
index 0000000000..f71486495b
--- /dev/null
+++ b/test/prism/fixtures/seattlerb/words_interp.txt
@@ -0,0 +1 @@
+%W(#{1}b)
diff --git a/test/prism/fixtures/single_method_call_with_bang.txt b/test/prism/fixtures/single_method_call_with_bang.txt
new file mode 100644
index 0000000000..929efb3053
--- /dev/null
+++ b/test/prism/fixtures/single_method_call_with_bang.txt
@@ -0,0 +1 @@
+foo!
diff --git a/test/prism/fixtures/single_quote_heredocs.txt b/test/prism/fixtures/single_quote_heredocs.txt
new file mode 100644
index 0000000000..0122b2726c
--- /dev/null
+++ b/test/prism/fixtures/single_quote_heredocs.txt
@@ -0,0 +1,3 @@
+<<-'EOS'
+ cd L:\Work\MG3710IQPro\Develop
+EOS
diff --git a/test/prism/fixtures/spanning_heredoc.txt b/test/prism/fixtures/spanning_heredoc.txt
new file mode 100644
index 0000000000..d09cb11b1f
--- /dev/null
+++ b/test/prism/fixtures/spanning_heredoc.txt
@@ -0,0 +1,63 @@
+# test regex, string, and lists that span a heredoc thanks to an escaped newline
+
+# ripper incorrectly creates a "b\nb" token instead of two separate string tokens
+pp <<-A.gsub(/b\
+a
+A
+b/, "")
+
+# ripper incorrectly creates a "d\nd" token instead of two separate string tokens
+pp <<-A, "d\
+c
+A
+d"
+
+# ripper gets this right
+pp <<-A, %q[f\
+e
+A
+f]
+
+# ripper incorrectly creates a "h\nh" token instead of two separate string tokens
+pp <<-A, %Q[h\
+g
+A
+h]
+
+# ripper can't parse this successfully, though ruby runs it correctly
+pp <<-A, %w[j\
+i
+A
+j]
+
+# ripper can't parse this successfully, though ruby runs it correctly
+# TODO: prism does not include the "\n" in "l\nl" in the AST like ruby does
+pp <<-A, %W[l\
+k
+A
+l]
+
+# ripper can't parse this successfully, though ruby runs it correctly
+pp <<-A, %i[n\
+m
+A
+n]
+
+# ripper gets this one wrong in the same way that prism does ...
+# TODO: prism does not include the "\n" in "p\np" in the AST like ruby does
+pp <<-A, %I[p\
+o
+A
+p]
+
+<<A; /\
+A
+(?<a>)/ =~ ''
+
+<<A; :'a
+A
+b'
+
+<<A; :"a
+A
+b"
diff --git a/test/prism/fixtures/spanning_heredoc_newlines.txt b/test/prism/fixtures/spanning_heredoc_newlines.txt
new file mode 100644
index 0000000000..32c9943aeb
--- /dev/null
+++ b/test/prism/fixtures/spanning_heredoc_newlines.txt
@@ -0,0 +1,23 @@
+<<A+%
+A
+
+
+<<A+%r
+A
+
+
+<<A+%q
+A
+
+
+<<A+%Q
+A
+
+
+<<A+%s
+A
+
+
+<<A+%x
+A
+
diff --git a/test/prism/fixtures/string_concatination_frozen_false.txt b/test/prism/fixtures/string_concatination_frozen_false.txt
new file mode 100644
index 0000000000..abe9301408
--- /dev/null
+++ b/test/prism/fixtures/string_concatination_frozen_false.txt
@@ -0,0 +1,5 @@
+# frozen_string_literal: false
+
+'foo' 'bar'
+
+'foo' 'bar' "baz#{bat}"
diff --git a/test/prism/fixtures/string_concatination_frozen_true.txt b/test/prism/fixtures/string_concatination_frozen_true.txt
new file mode 100644
index 0000000000..829777f0a7
--- /dev/null
+++ b/test/prism/fixtures/string_concatination_frozen_true.txt
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+'foo' 'bar'
+
+'foo' 'bar' "baz#{bat}"
diff --git a/test/prism/fixtures/strings.txt b/test/prism/fixtures/strings.txt
new file mode 100644
index 0000000000..1419f975b7
--- /dev/null
+++ b/test/prism/fixtures/strings.txt
@@ -0,0 +1,185 @@
+%%abc%
+
+%^abc^
+
+%&abc&
+
+%*abc*
+
+%_abc_
+
+%+abc+
+
+%-abc-
+
+%:abc:
+
+%;abc;
+
+%'abc'
+
+%~abc~
+
+%?abc?
+
+%w{ }
+
+%/abc/
+
+%`abc`
+
+"#@@foo"
+
+%\abc\
+
+%{aaa #{bbb} ccc}
+
+%[foo[]]
+
+"foo" +
+#
+"bar"
+
+"
+foo\
+b\nar
+"
+
+"foo
+\nbar\n\n
+a\nb\n\nc\n"
+
+%q{abc}
+
+%s[abc]
+
+%{abc}
+
+''
+
+"abc"
+
+"#@---"
+
+"aaa #{bbb} ccc"
+
+'abc'
+
+%w[a b c]
+
+%w[a[] b[[]] c[]]
+
+%w[foo\ bar \#{1}]
+
+%w[foo\ bar baz]
+
+%w[foo\ bar\\ baz\\\
+ bat]
+
+%W[#{foo}\
+bar
+baz #{bat}
+]
+
+%w(foo\n)
+
+%w(foo\
+)
+
+%w(foo \n)
+
+%W(foo\
+bar)
+
+%w[foo bar]
+
+%w[
+ a
+ b c
+ d
+]
+
+%w[
+ foo\nbar baz\n\n\
+ bat\n\\\n\foo
+]
+
+%W[
+ foo\nbar baz\n\n\
+ bat\n\\\n\foo
+]
+
+%w[foo\
+ bar
+ baz\\
+ bat
+ 1\n
+ 2
+ 3\\n
+]
+
+%W[foo\
+ bar
+ baz\\
+ bat
+ 1\n
+ 2
+ 3\\n
+]
+
+%W[f\u{006f 006f}]
+
+%W[a b#{c}d e]
+
+%W[a b c]
+
+%w[
+ a
+ b
+ c
+]
+
+'\' foo \' bar'
+
+'\\ foo \\ bar'
+
+'foo\
+bar\\
+baz
+'
+
+"#$foo"
+
+"#@foo"
+
+"\x7 \x23 \x61"
+
+"\7 \43 \141"
+
+"ち\xE3\x81\xFF"
+
+"\777"
+
+%[abc]
+
+%(abc)
+
+%@abc@
+
+%$abc$
+
+?a
+
+?a "a"
+
+%Q{abc}
+
+%Q(\«)
+
+%q(\«)
+
+%^#$^#
+
+%@#@#
+
+"#{"#{B} C"} D"
diff --git a/test/prism/fixtures/super.txt b/test/prism/fixtures/super.txt
new file mode 100644
index 0000000000..cd7aaf992e
--- /dev/null
+++ b/test/prism/fixtures/super.txt
@@ -0,0 +1,17 @@
+super
+
+super()
+
+super(1)
+
+super(1, 2, 3)
+
+super &:foo
+
+super(&:foo)
+
+super {}
+
+super(1, 2, 3) {}
+
+super(1, 2, 3, &:foo)
diff --git a/test/prism/fixtures/symbols.txt b/test/prism/fixtures/symbols.txt
new file mode 100644
index 0000000000..34895b9e9f
--- /dev/null
+++ b/test/prism/fixtures/symbols.txt
@@ -0,0 +1,104 @@
+:'abc'
+
+:"#{var}"
+
+:"abc#{1}"
+
+:"
+foo\
+b\nar
+"
+
+:"
+foo\
+b\nar
+#{}
+"
+
+[:Υ, :ά, :ŗ, :ρ]
+
+:-@
+
+:-
+
+:%
+
+:|
+
+:+@
+
+:+
+
+:/
+
+:**
+
+:*
+
+:~@
+
+[1, 1.0, 1r, 1i]
+
+:~
+
+:a
+
+%i[a b c]
+
+%i[a b#{1} #{2}c d#{3}f]
+
+%I[a b#{1} #{2}c d#{3}f]
+
+:@@a
+
+:👍
+
+%i[a\b]
+
+:$a
+
+:@a
+
+:do
+
+:&
+
+:`
+
+:!@
+
+:!~
+
+:!
+
+:[]
+
+:[]=
+
+:^
+
+:==
+
+:===
+
+:=~
+
+:>=
+
+:>>
+
+:>
+
+:<=>
+
+:<=
+
+:<<
+
+:<
+
+:__LINE__
+
+:__FILE__
+
+:__ENCODING__
diff --git a/test/prism/fixtures/ternary_operator.txt b/test/prism/fixtures/ternary_operator.txt
new file mode 100644
index 0000000000..79d2d7d837
--- /dev/null
+++ b/test/prism/fixtures/ternary_operator.txt
@@ -0,0 +1,15 @@
+a ? b : c
+
+a ? defined? b : defined? c
+
+empty??true:nil
+
+empty??false:nil
+
+empty??nil:nil
+
+a??nil:nil
+
+a ?var1 : var2
+
+nil??_a =2:1
diff --git a/test/prism/fixtures/tilde_heredocs.txt b/test/prism/fixtures/tilde_heredocs.txt
new file mode 100644
index 0000000000..cca47ef00b
--- /dev/null
+++ b/test/prism/fixtures/tilde_heredocs.txt
@@ -0,0 +1,97 @@
+<<~EOF
+ a
+#{1}
+ a
+EOF
+
+<<~EOF
+ a
+EOF
+
+<<~EOF
+ a
+ b
+ c
+EOF
+
+<<~EOF
+ #{1} a
+EOF
+
+<<~EOF
+ a #{1}
+EOF
+
+<<~EOF
+ a
+ #{1}
+EOF
+
+<<~EOF
+ a
+ #{1}
+EOF
+
+<<~EOF
+ a
+ b
+EOF
+
+<<~EOF
+ a
+ b
+EOF
+
+<<~EOF
+ a
+ b
+EOF
+
+<<~'EOF'
+ a #{1}
+EOF
+
+<<~EOF
+ a
+ b
+EOF
+
+<<~EOF
+ a
+ b
+EOF
+
+<<~EOF
+ a
+ b
+EOF
+
+<<~EOF
+ a
+
+ b
+EOF
+
+<<~EOF
+ a
+
+ b
+EOF
+
+<<~EOF
+ a
+
+
+
+ b
+EOF
+
+<<~EOF
+
+ #{1}a
+ EOF
+
+<<~EOT
+ #{1}
+ b
+EOT
diff --git a/test/prism/fixtures/unary_method_calls.txt b/test/prism/fixtures/unary_method_calls.txt
new file mode 100644
index 0000000000..a8327d23cc
--- /dev/null
+++ b/test/prism/fixtures/unary_method_calls.txt
@@ -0,0 +1,8 @@
+42.~@
+42.!@
+
+-
+42
+
++
+42
diff --git a/test/prism/fixtures/undef.txt b/test/prism/fixtures/undef.txt
new file mode 100644
index 0000000000..129c349433
--- /dev/null
+++ b/test/prism/fixtures/undef.txt
@@ -0,0 +1,17 @@
+undef a
+
+undef a, b
+
+undef if
+
+undef <=>
+
+undef :a
+
+undef :a, :b, :c
+
+undef :'abc'
+
+undef :"abc#{1}"
+
+undef Constant
diff --git a/test/prism/fixtures/unescaping.txt b/test/prism/fixtures/unescaping.txt
new file mode 100644
index 0000000000..e2da5a696c
--- /dev/null
+++ b/test/prism/fixtures/unescaping.txt
@@ -0,0 +1,9 @@
+["\c#{1}"]
+
+/\c#{1}/
+
+"\c#{1}"
+
+<<~HERE
+ \c#{1}
+HERE
diff --git a/test/prism/fixtures/unless.txt b/test/prism/fixtures/unless.txt
new file mode 100644
index 0000000000..678d58991b
--- /dev/null
+++ b/test/prism/fixtures/unless.txt
@@ -0,0 +1,14 @@
+unless true; 1; end
+
+unless true
+1 else 2 end
+
+1 unless true
+
+tap { break unless true }
+
+tap { next unless true }
+
+return unless true
+
+foo :a, :b unless bar?
diff --git a/test/prism/fixtures/unparser/LICENSE b/test/prism/fixtures/unparser/LICENSE
new file mode 100644
index 0000000000..44863d7afb
--- /dev/null
+++ b/test/prism/fixtures/unparser/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2013 Markus Schirp
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/test/prism/fixtures/unparser/corpus/literal/alias.txt b/test/prism/fixtures/unparser/corpus/literal/alias.txt
new file mode 100644
index 0000000000..fb06a295e8
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/alias.txt
@@ -0,0 +1,2 @@
+alias $foo $bar
+alias :foo :bar
diff --git a/test/prism/fixtures/unparser/corpus/literal/assignment.txt b/test/prism/fixtures/unparser/corpus/literal/assignment.txt
new file mode 100644
index 0000000000..84a74e8928
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/assignment.txt
@@ -0,0 +1,53 @@
+$a = 1
+($a, $b) = [1, 2]
+((a,), b) = 1
+(*a) = []
+(*foo) = [1, 2]
+(@@a, @@b) = [1, 2]
+(@a, @b) = [1, 2]
+(a, (b, c)) = [1, [2, 3]]
+(a, *) = [1, 2]
+(a, *foo) = [1, 2]
+(a, b) = [1, 2]
+(a, b) = foo
+(a,) = foo
+(a.foo, a.bar) = [1, 2]
+(a[*foo], a[1]) = [1, 2]
+(a[0], a[1]) = [1, 2]
+(*c.foo) = 1
+::Foo = ::Bar
+@@a = 1
+@a = 1
+CONST = 1
+Name::Spaced::CONST = 1
+a = ((b, c) = 1)
+a = 1
+foo = foo()
+foo.[]=()
+foo.[]=(1, 2)
+foo.[]=true
+foo[*index] = value
+foo[1..2] = value
+foo[] = 1
+foo[a, b] = value
+foo[index] = value
+x = %()
+x.x=%()
+x[%()] = bar
+a[%()] ||= bar
+@a ||= %()
+x = <<-HEREDOC
+ #{}
+HEREDOC
+x.x=<<-HEREDOC
+ #{}
+HEREDOC
+x[] = <<-HEREDOC
+ #{}
+HEREDOC
+a[<<-HEREDOC] ||= bar
+ #{}
+HEREDOC
+@a ||= <<-HEREDOC
+ #{}
+HEREDOC
diff --git a/test/prism/fixtures/unparser/corpus/literal/block.txt b/test/prism/fixtures/unparser/corpus/literal/block.txt
new file mode 100644
index 0000000000..b2baf1dc12
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/block.txt
@@ -0,0 +1,96 @@
+foo {
+}
+foo { |a|
+}
+foo { |a,|
+}
+foo { |a,; x|
+}
+foo { |a, b|
+}
+foo(1) {
+ nil
+}
+foo { |a, *b|
+ nil
+}
+foo { |a, *|
+ nil
+}
+foo {
+ bar
+}
+foo.bar { |(a, b), c|
+ d
+}
+foo.bar { |*a; b|
+}
+foo.bar { |a; b|
+}
+foo.bar { |; a, b|
+}
+foo.bar { |*|
+ d
+}
+foo.bar { |(*)|
+ d
+}
+foo.bar { |((*))|
+ d
+}
+foo.bar { |(a, (*))|
+ d
+}
+foo.bar { |(a, b)|
+ d
+}
+foo.bar {
+}.baz
+m do
+rescue Exception => e
+end
+m do
+ foo
+rescue Exception => bar
+ bar
+end
+m do
+ bar
+rescue SomeError, *bar
+ baz
+end
+m do
+ bar
+rescue SomeError, *bar => exception
+ baz
+end
+m do
+ bar
+rescue *bar
+ baz
+end
+m do
+ bar
+rescue LoadError
+end
+m do
+ bar
+rescue
+else
+ baz
+end
+m do
+ bar
+rescue *bar => exception
+ baz
+end
+m do
+ensure
+end
+m do
+rescue
+ensure
+end
+bar {
+ _1 + _2
+}
diff --git a/test/prism/fixtures/unparser/corpus/literal/case.txt b/test/prism/fixtures/unparser/corpus/literal/case.txt
new file mode 100644
index 0000000000..c455fd7c39
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/case.txt
@@ -0,0 +1,37 @@
+case
+when bar
+ baz
+when baz
+ bar
+end
+case foo
+when bar
+when baz
+ bar
+end
+case foo
+when bar
+ baz
+when baz
+ bar
+end
+case foo
+when bar, baz
+ :other
+end
+case foo
+when *bar
+ :value
+end
+case foo
+when bar
+ baz
+else
+ :foo
+end
+case foo
+when *bar | baz
+end
+case foo
+when *bar.baz=1
+end
diff --git a/test/prism/fixtures/unparser/corpus/literal/class.txt b/test/prism/fixtures/unparser/corpus/literal/class.txt
new file mode 100644
index 0000000000..f0198625e9
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/class.txt
@@ -0,0 +1,35 @@
+class A
+end
+
+class << a
+end
+
+class << a
+ b
+end
+
+class A::B
+end
+
+class A::B::C
+end
+
+class A < B
+end
+
+class A < B::C
+end
+
+class A::B < C::D
+end
+
+class A
+ include(B.new)
+
+ def foo
+ :bar
+ end
+end
+
+class ::A
+end
diff --git a/test/prism/fixtures/unparser/corpus/literal/def.txt b/test/prism/fixtures/unparser/corpus/literal/def.txt
new file mode 100644
index 0000000000..61339bd4a6
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/def.txt
@@ -0,0 +1,134 @@
+def foo
+ a
+rescue
+ b
+else
+ c
+ensure
+ d
+end
+
+def foo
+ a rescue b
+rescue
+ b
+else
+ c
+ensure
+ d
+end
+
+def foo(bar:, baz:)
+end
+
+def foo
+end
+
+def foo
+ bar
+end
+
+def foo
+ foo
+rescue
+ bar
+ensure
+ baz
+end
+
+def foo
+ bar
+ensure
+ baz
+end
+
+def foo
+ bar
+rescue
+ baz
+end
+
+def foo(bar)
+ bar
+end
+
+def foo(bar, baz)
+ bar
+end
+
+def foo(bar = ())
+ bar
+end
+
+def foo(bar = (baz; nil))
+end
+
+def foo(bar = true)
+ bar
+end
+
+def foo(bar, baz = true)
+ bar
+end
+
+def foo(bar: 1)
+end
+
+def foo(bar: baz)
+end
+
+def foo(bar: bar())
+end
+
+def foo(*)
+ bar
+end
+
+def foo(*bar)
+ bar
+end
+
+def foo(bar, *baz)
+ bar
+end
+
+def foo(baz = true, *bor)
+ bar
+end
+
+def foo(baz = true, *bor, &block)
+ bar
+end
+
+def foo(bar, baz = true, *bor)
+ bar
+end
+
+def foo(&block)
+ bar
+end
+
+def foo(bar, &block)
+ bar
+end
+
+def foo
+ bar
+ baz
+end
+
+def f(((a)))
+end
+
+def foo(bar:, baz: "value")
+end
+
+def f
+ <<-HEREDOC
+ #{}
+ HEREDOC
+end
+
+def f
+ %()
+end
diff --git a/test/prism/fixtures/unparser/corpus/literal/defined.txt b/test/prism/fixtures/unparser/corpus/literal/defined.txt
new file mode 100644
index 0000000000..65e7c370fd
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/defined.txt
@@ -0,0 +1,3 @@
+defined?(@foo)
+defined?(Foo)
+defined?(((a, b) = [1, 2]))
diff --git a/test/prism/fixtures/unparser/corpus/literal/defs.txt b/test/prism/fixtures/unparser/corpus/literal/defs.txt
new file mode 100644
index 0000000000..b70aa9efc5
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/defs.txt
@@ -0,0 +1,40 @@
+def self.foo
+end
+
+def self.foo
+ bar
+end
+
+def self.foo
+ bar
+ baz
+end
+
+def Foo.bar
+ bar
+end
+
+def (foo { |bar|
+}).bar
+ bar
+end
+
+def (foo(1)).bar
+ bar
+end
+
+def (Foo::Bar.baz).bar
+ baz
+end
+
+def (Foo::Bar).bar
+ baz
+end
+
+def Foo.bar
+ baz
+end
+
+def foo.bar
+ baz
+end
diff --git a/test/prism/fixtures/unparser/corpus/literal/dstr.txt b/test/prism/fixtures/unparser/corpus/literal/dstr.txt
new file mode 100644
index 0000000000..8a912d28ed
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/dstr.txt
@@ -0,0 +1,37 @@
+if true
+ "#{}a"
+end
+if true
+ <<-HEREDOC
+a
+#{}a
+b
+ HEREDOC
+ x
+end
+<<-HEREDOC
+\#{}\#{}
+#{}
+#{}
+#{}
+HEREDOC
+<<-HEREDOC rescue nil
+#{}
+a
+HEREDOC
+"a#$1"
+"a#$a"
+"a#@a"
+"a#@@a"
+if true
+ return <<-HEREDOC
+ #{42}
+ HEREDOC
+end
+foo(<<-HEREDOC)
+ #{bar}
+HEREDOC
+foo(<<-HEREDOC) { |x|
+ #{bar}
+HEREDOC
+}
diff --git a/test/prism/fixtures/unparser/corpus/literal/empty.txt b/test/prism/fixtures/unparser/corpus/literal/empty.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/empty.txt
diff --git a/test/prism/fixtures/unparser/corpus/literal/empty_begin.txt b/test/prism/fixtures/unparser/corpus/literal/empty_begin.txt
new file mode 100644
index 0000000000..6a452c185a
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/empty_begin.txt
@@ -0,0 +1 @@
+()
diff --git a/test/prism/fixtures/unparser/corpus/literal/flipflop.txt b/test/prism/fixtures/unparser/corpus/literal/flipflop.txt
new file mode 100644
index 0000000000..139904a53f
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/flipflop.txt
@@ -0,0 +1,10 @@
+if ((i == 4)..(i == 4))
+ foo
+end
+if ((i == 4)...(i == 4))
+ foo
+end
+if ..foo
+end
+if foo..;
+end
diff --git a/test/prism/fixtures/unparser/corpus/literal/for.txt b/test/prism/fixtures/unparser/corpus/literal/for.txt
new file mode 100644
index 0000000000..4c19a352d9
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/for.txt
@@ -0,0 +1,12 @@
+bar(for a in bar do
+ baz
+end)
+for a in bar do
+ baz
+end
+for (a, *b) in bar do
+ baz
+end
+for (a, b) in bar do
+ baz
+end
diff --git a/test/prism/fixtures/unparser/corpus/literal/hookexe.txt b/test/prism/fixtures/unparser/corpus/literal/hookexe.txt
new file mode 100644
index 0000000000..08f14f47b3
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/hookexe.txt
@@ -0,0 +1,7 @@
+BEGIN {
+ foo
+}
+bar
+END {
+ baz
+}
diff --git a/test/prism/fixtures/unparser/corpus/literal/if.txt b/test/prism/fixtures/unparser/corpus/literal/if.txt
new file mode 100644
index 0000000000..0c13801f9e
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/if.txt
@@ -0,0 +1,36 @@
+if /foo/
+ bar
+end
+if 3
+ 9
+end
+if 4
+ 5
+else
+ 6
+end
+unless 3
+ nil
+end
+unless 3
+ 9
+end
+if foo
+end
+
+module A
+ foo = bar if foo
+end
+
+module B
+ foo = bar unless foo
+end
+unless foo
+ foo = bar
+end
+if foo { |pair|
+ pair
+}
+ pair = :foo
+ foo
+end
diff --git a/test/prism/fixtures/unparser/corpus/literal/kwbegin.txt b/test/prism/fixtures/unparser/corpus/literal/kwbegin.txt
new file mode 100644
index 0000000000..6cc1e74ca6
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/kwbegin.txt
@@ -0,0 +1,80 @@
+begin
+rescue
+end
+
+begin
+ensure
+end
+
+begin
+ a
+end
+
+begin
+ a
+rescue
+ b
+end
+
+begin
+ a
+ b
+rescue
+ b
+end
+
+begin
+rescue A
+end
+
+begin
+rescue A => foo
+end
+
+begin
+ a
+rescue A
+ b
+rescue B
+ c
+ensure
+ d
+end
+
+begin
+ begin
+ foo
+ bar
+ rescue
+ end
+rescue
+ baz
+ bar
+end
+
+begin
+ raise(Exception) rescue foo = bar
+rescue Exception
+end
+
+begin
+ foo
+rescue => bar
+ bar
+end
+
+begin
+ foo
+rescue Exception, Other => bar
+ bar
+end
+
+begin
+ bar
+rescue SomeError, *bar => exception
+ baz
+end
+
+class << self
+ undef :bar rescue nil
+end
diff --git a/test/prism/fixtures/unparser/corpus/literal/lambda.txt b/test/prism/fixtures/unparser/corpus/literal/lambda.txt
new file mode 100644
index 0000000000..4eb722dad1
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/lambda.txt
@@ -0,0 +1,13 @@
+lambda {
+}
+lambda { |a, b|
+ a
+}
+->() {
+}
+->(a) {
+}
+->(a, b) {
+}
+->(a, b; c) {
+}
diff --git a/test/prism/fixtures/unparser/corpus/literal/literal.txt b/test/prism/fixtures/unparser/corpus/literal/literal.txt
new file mode 100644
index 0000000000..2fc7cd1d79
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/literal.txt
@@ -0,0 +1,91 @@
+{ "foo" => <<-HEREDOC, "bar" => :baz }
+ #{}
+HEREDOC
+{ "foo" => %(), "bar" => :baz }
+["foo", %()]
+a(<<-HEREDOC).a
+ #{}
+HEREDOC
+a(%()).a
+{ "foo" => <<-HEREDOC, **baz }
+ #{}
+HEREDOC
+{ "foo" => %(), **baz }
+"#@a #@@a #$a"
+0
+++1
+1
+1
+1r
+1.5r
+1.3r
+5i
+-5i
+0.6i
+-0.6i
+1000000000000000000000000000000i
+1ri
+"foo" "bar"
+"foobar #{baz}"
+"foo#{1}bar"
+"\\\\#{}"
+"#{}\#{}"
+"\#{}#{}"
+"foo\\\#{@bar}"
+"\""
+"foo bar"
+"foo\nbar"
+`foo`
+`foo#{@bar}`
+`)`
+`\``
+`"`
+:foo
+:"A B"
+:foo
+:"A B"
+:"A\"B"
+:""
+/foo/
+/[^-+',.\/:@[:alnum:]\[\]]+/
+/foo#{@bar}/
+/foo#{@bar}/imx
+/#{"\u0000"}/
+/\n/
+/\n/
+/\n/x
+/\/\//x
+:"foo#{bar}baz"
+:"#{"foo"}"
+(0.0 / 0.0)..1
+1..(0.0 / 0.0)
+(0.0 / 0.0)..100
+-0.1
+0.1
+[1, 2]
+[1, (), n2]
+[1]
+[]
+[1, *@foo]
+[*@foo, 1]
+[*@foo, *@baz]
+{}
+{ () => () }
+{ 1 => 2 }
+{ 1 => 2, 3 => 4 }
+{ a: (1 rescue foo), b: 2 }
+{ a: 1, b: 2 }
+{ a: :a }
+{ :"a b" => 1 }
+{ :-@ => 1 }
+"#{}
+#{}\na"
+foo {
+ "#{}
+#{}\na"
+}
+:"a\\
+b"
+` x
+#{foo}
+#`
diff --git a/test/prism/fixtures/unparser/corpus/literal/module.txt b/test/prism/fixtures/unparser/corpus/literal/module.txt
new file mode 100644
index 0000000000..cec03f3bfd
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/module.txt
@@ -0,0 +1,16 @@
+module A
+end
+
+module A::B
+end
+
+module A::B::C
+end
+
+module A
+ include(B.new)
+
+ def foo
+ :bar
+ end
+end
diff --git a/test/prism/fixtures/unparser/corpus/literal/opasgn.txt b/test/prism/fixtures/unparser/corpus/literal/opasgn.txt
new file mode 100644
index 0000000000..5858d773d0
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/opasgn.txt
@@ -0,0 +1,24 @@
+a += 2
+a -= 2
+a **= 2
+a *= 2
+a /= 2
+a &&= b
+a ||= 2
+(a ||= 2).bar
+(h ||= {})[k] = v
+a.b += 2
+a.b -= 2
+a.b **= 2
+a.b *= 2
+a.b /= 2
+a.b &&= b
+a.b ||= 2
+a[b] += 2
+a[b] -= 2
+a[b] **= 2
+a[b] *= 2
+a[b] /= 2
+a[b] &&= b
+a[b] ||= 2
+foo.A += 1
diff --git a/test/prism/fixtures/unparser/corpus/literal/pattern.txt b/test/prism/fixtures/unparser/corpus/literal/pattern.txt
new file mode 100644
index 0000000000..7cfaa4dc67
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/pattern.txt
@@ -0,0 +1,41 @@
+case foo
+in A[1, 2, *a, 3] then
+ true
+in [1, 2, ] then
+ y
+in A(x:) then
+ true
+in {**a} then
+ true
+in {} if true then
+ true
+in [x, y, *] then
+ true
+in {a: 1, aa: 2} then
+ true
+in {} then
+ true
+in {**nil} then
+ true
+in {"a": 1} then
+ true
+in 1 | 2 then
+ true
+in 1 => a then
+ true
+in ^x then
+ true
+in 1
+in 2 then
+ true
+else
+ true
+end
+case foo
+in A[1, 2, *a, 3]
+end
+case foo
+in A
+else
+end
+1 in [a]
diff --git a/test/prism/fixtures/unparser/corpus/literal/pragma.txt b/test/prism/fixtures/unparser/corpus/literal/pragma.txt
new file mode 100644
index 0000000000..4f6dd71b38
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/pragma.txt
@@ -0,0 +1,4 @@
+__ENCODING__
+__FILE__
+__LINE__
+__dir__
diff --git a/test/prism/fixtures/unparser/corpus/literal/range.txt b/test/prism/fixtures/unparser/corpus/literal/range.txt
new file mode 100644
index 0000000000..eb1f3874c0
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/range.txt
@@ -0,0 +1,4 @@
+(1..)
+1..2
+(1...)
+1...2
diff --git a/test/prism/fixtures/unparser/corpus/literal/rescue.txt b/test/prism/fixtures/unparser/corpus/literal/rescue.txt
new file mode 100644
index 0000000000..a787816808
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/rescue.txt
@@ -0,0 +1,3 @@
+foo rescue bar
+foo rescue return bar
+x = (foo rescue return bar)
diff --git a/test/prism/fixtures/unparser/corpus/literal/send.txt b/test/prism/fixtures/unparser/corpus/literal/send.txt
new file mode 100644
index 0000000000..1e9c2a94be
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/send.txt
@@ -0,0 +1,84 @@
+module A
+ foo ||= ((a, _) = b)
+end
+
+module A
+ local = 1
+ local.bar
+end
+class A
+end.bar
+module A
+end.bar
+begin
+rescue
+end.bar
+case (def foo
+end; :bar)
+when bar
+end.baz
+case foo
+when bar
+end.baz
+class << self
+end.bar
+def self.foo
+end.bar
+def foo
+end.bar
+until foo
+end.bar
+while foo
+end.bar
+loop {
+}.bar
+if foo
+end.baz
+(/bar/ =~ :foo).foo
+(1..2).max
+(foo =~ /bar/).foo
+/bar/ =~ :foo
+/bar/ =~ foo
+1..2.max
+A.foo
+FOO()
+a&.b
+a.foo
+foo
+foo << (bar * baz)
+foo =~ /bar/
+foo(&(foo || bar))
+foo(&block)
+foo(*args, &block)
+foo(*arguments)
+foo(1, 2)
+foo(bar)
+foo(bar, *args)
+foo(foo =~ /bar/)
+foo.bar(&baz)
+foo.bar(*arga, foo, *argb)
+foo.bar(*args)
+foo.bar(*args, foo)
+foo.bar(:baz, &baz)
+foo.bar(baz: boz)
+foo.bar(foo, "baz" => boz)
+foo.bar(foo, *args)
+foo.bar(foo, *args, &block)
+foo.bar(foo, {})
+foo.bar({ foo: boz }, boz)
+foo.bar=:baz
+foo(a: b)
+foo.&(a: b)
+foo.&(**a)
+foo[*baz]
+foo[1, 2]
+foo[]
+self.foo
+self.foo=:bar
+(a + b) / (c - d)
+(a + b) / c.-(e, f)
+(a + b) / c.-(*f)
+x(**foo)
+foo&.!
+foo.~(b)
+a&.+(b)
diff --git a/test/prism/fixtures/unparser/corpus/literal/since/27.txt b/test/prism/fixtures/unparser/corpus/literal/since/27.txt
new file mode 100644
index 0000000000..c332f9e48e
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/since/27.txt
@@ -0,0 +1,4 @@
+-> {
+ _1 + _2
+}
+(..1)
diff --git a/test/prism/fixtures/unparser/corpus/literal/since/30.txt b/test/prism/fixtures/unparser/corpus/literal/since/30.txt
new file mode 100644
index 0000000000..b73328a4b0
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/since/30.txt
@@ -0,0 +1,4 @@
+1 => [a]
+1 => [*]
+1 in [*, 42, *]
+1 in [*, a, *foo]
diff --git a/test/prism/fixtures/unparser/corpus/literal/since/31.txt b/test/prism/fixtures/unparser/corpus/literal/since/31.txt
new file mode 100644
index 0000000000..504eb94d5b
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/since/31.txt
@@ -0,0 +1,7 @@
+def foo(&)
+ bar(&)
+end
+
+def foo(a, &)
+ bar(&)
+end
diff --git a/test/prism/fixtures/unparser/corpus/literal/since/32.txt b/test/prism/fixtures/unparser/corpus/literal/since/32.txt
new file mode 100644
index 0000000000..b8e096d8fc
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/since/32.txt
@@ -0,0 +1,11 @@
+def foo(argument, **)
+ bar(argument, **)
+end
+
+def foo(argument, *)
+ bar(argument, *)
+end
+
+def foo(**)
+ { default: 1, ** }
+end
diff --git a/test/prism/fixtures/unparser/corpus/literal/singletons.txt b/test/prism/fixtures/unparser/corpus/literal/singletons.txt
new file mode 100644
index 0000000000..496e6a41ce
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/singletons.txt
@@ -0,0 +1,4 @@
+false
+nil
+self
+true
diff --git a/test/prism/fixtures/unparser/corpus/literal/super.txt b/test/prism/fixtures/unparser/corpus/literal/super.txt
new file mode 100644
index 0000000000..0e73e6f052
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/super.txt
@@ -0,0 +1,21 @@
+super
+super()
+super(a)
+super(a, b)
+super(&block)
+super(a, &block)
+super(a {
+ foo
+})
+super {
+ foo
+}
+super(a) {
+ foo
+}
+super() {
+ foo
+}
+super(a, b) {
+ foo
+}
diff --git a/test/prism/fixtures/unparser/corpus/literal/unary.txt b/test/prism/fixtures/unparser/corpus/literal/unary.txt
new file mode 100644
index 0000000000..6992d86bb0
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/unary.txt
@@ -0,0 +1,9 @@
+!1
+!(!1)
+!(!(foo || bar))
+!(!1).baz
+~a
+-a
++a
+-(-a).foo
++(+a).foo
diff --git a/test/prism/fixtures/unparser/corpus/literal/undef.txt b/test/prism/fixtures/unparser/corpus/literal/undef.txt
new file mode 100644
index 0000000000..a65d8d0cc4
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/undef.txt
@@ -0,0 +1,2 @@
+undef :foo
+undef :foo, :bar
diff --git a/test/prism/fixtures/unparser/corpus/literal/variables.txt b/test/prism/fixtures/unparser/corpus/literal/variables.txt
new file mode 100644
index 0000000000..1de938f376
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/variables.txt
@@ -0,0 +1,10 @@
+a
+@a
+@@a
+$a
+$1
+$`
+CONST
+SCOPED::CONST
+::TOPLEVEL
+::TOPLEVEL::CONST
diff --git a/test/prism/fixtures/unparser/corpus/literal/while.txt b/test/prism/fixtures/unparser/corpus/literal/while.txt
new file mode 100644
index 0000000000..19a60ef5ff
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/literal/while.txt
@@ -0,0 +1,73 @@
+module A
+ foo { |bar|
+ while foo
+ foo = bar
+ end
+ }
+end
+
+def foo
+ foo = bar while foo != baz
+end
+
+module A
+ foo = bar while foo
+end
+
+module A
+ foo = bar until foo
+end
+
+module A
+ while foo
+ foo = bar
+ end
+end
+
+module A
+ each { |baz|
+ while foo
+ foo = bar
+ end
+ }
+end
+
+module A
+ each { |foo|
+ while foo
+ foo = bar
+ end
+ }
+end
+x = (begin
+ foo
+end while baz)
+begin
+ foo
+end while baz
+begin
+ foo
+ bar
+end until baz
+begin
+ foo
+ bar
+end while baz
+while false
+end
+while false
+ 3
+end
+while (foo {
+})
+ :body
+end
+until false
+end
+until false
+ 3
+end
+until (foo {
+})
+ :body
+end
diff --git a/test/prism/fixtures/unparser/corpus/semantic/and.txt b/test/prism/fixtures/unparser/corpus/semantic/and.txt
new file mode 100644
index 0000000000..43d1712445
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/semantic/and.txt
@@ -0,0 +1,8 @@
+a...b or c...d
+a...b and c...d
+
+if a...b or c...d
+end
+
+if a...b and c...d
+end
diff --git a/test/prism/fixtures/unparser/corpus/semantic/block.txt b/test/prism/fixtures/unparser/corpus/semantic/block.txt
new file mode 100644
index 0000000000..5891690025
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/semantic/block.txt
@@ -0,0 +1,26 @@
+foo do
+end
+
+foo do
+rescue
+end
+
+foo do
+ nil rescue nil
+ nil
+end
+
+foo do |a|
+end
+
+foo(<<-DOC) do |a|
+ b
+DOC
+ a
+end
+
+foo(<<-DOC) do
+ b
+DOC
+ a
+end
diff --git a/test/prism/fixtures/unparser/corpus/semantic/def.txt b/test/prism/fixtures/unparser/corpus/semantic/def.txt
new file mode 100644
index 0000000000..7574619392
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/semantic/def.txt
@@ -0,0 +1,7 @@
+def foo
+ (a - b)
+end
+
+def foo
+ a rescue Exception
+end
diff --git a/test/prism/fixtures/unparser/corpus/semantic/dstr.txt b/test/prism/fixtures/unparser/corpus/semantic/dstr.txt
new file mode 100644
index 0000000000..919e736077
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/semantic/dstr.txt
@@ -0,0 +1,127 @@
+<<DOC
+DOC
+
+<<'DOC'
+DOC
+
+<<~DOC
+DOC
+
+<<~'DOC'
+DOC
+
+<<DOC
+ a
+DOC
+
+<<'DOC'
+ a
+DOC
+
+<<DOC
+ a
+ #{}
+DOC
+
+<<~DOC
+ a
+ #{}
+DOC
+
+<<~DOC
+ a
+ #{}
+ b
+DOC
+
+<<~DOC
+ a
+ b
+DOC
+
+<<'DOC'
+a
+
+b
+DOC
+
+<<'DOC'
+ a
+
+ b
+DOC
+
+<<'DOC'
+ a\nb
+DOC
+
+<<DOC
+#{}a
+ #{}a
+DOC
+
+<<DOC
+ #{}
+ \#{}
+DOC
+
+<<DOC
+ a#{}b
+ c
+DOC
+
+<<~DOC
+ #{}
+DOC
+
+if true
+ <<~DOC
+ #{}
+ DOC
+end
+
+if true
+ <<~DOC
+ b#{}
+ DOC
+end
+
+if true
+ <<~DOC
+ #{}a
+ DOC
+end
+
+if true
+ <<-'DOC'
+ a
+
+ b
+ DOC
+end
+
+"#{}a"
+
+%(\n"#{}"\n)
+
+%Q(-\n"#{}"\n)
+
+"a
+#{}
+b"
+
+"a\n#{}
+b"
+
+"a
+#{}\nb"
+
+'a' \
+"#{}"
+
+"" "" ""
+
+"a#{@a}" "b"
+"a#@a" "b"
+"a#$a" "b"
+"a#@@a" "b"
diff --git a/test/prism/fixtures/unparser/corpus/semantic/kwbegin.txt b/test/prism/fixtures/unparser/corpus/semantic/kwbegin.txt
new file mode 100644
index 0000000000..d275a96a5c
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/semantic/kwbegin.txt
@@ -0,0 +1,42 @@
+begin
+rescue
+end
+
+begin
+rescue
+else
+end
+
+begin
+ a
+end
+
+begin
+ a
+rescue
+ b
+end
+
+begin
+ a
+ b
+rescue
+ b
+end
+
+begin
+rescue A
+else
+end
+
+begin; rescue A; else; end
+
+begin
+ a
+rescue A
+ b
+rescue B
+ c
+ensure
+ d
+end
diff --git a/test/prism/fixtures/unparser/corpus/semantic/literal.txt b/test/prism/fixtures/unparser/corpus/semantic/literal.txt
new file mode 100644
index 0000000000..c424db5a53
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/semantic/literal.txt
@@ -0,0 +1,14 @@
+1.0r
+-0r
+0x1
+1_000
+1e10
+10e10000000000
+-10e10000000000
+?c
+%r(/)
+%r(\))
+%r(#{@bar}baz)
+10.2e10000000000
+-10.2e10000000000
+w(foo bar)
diff --git a/test/prism/fixtures/unparser/corpus/semantic/opasgn.txt b/test/prism/fixtures/unparser/corpus/semantic/opasgn.txt
new file mode 100644
index 0000000000..8b4bc5d239
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/semantic/opasgn.txt
@@ -0,0 +1 @@
+y["#{42}\n"] += "#{42}\n"
diff --git a/test/prism/fixtures/unparser/corpus/semantic/send.txt b/test/prism/fixtures/unparser/corpus/semantic/send.txt
new file mode 100644
index 0000000000..a65b27d2f2
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/semantic/send.txt
@@ -0,0 +1,6 @@
+foo
+foo(1)
+
+a.===(b).c == d
+
+a == d.c.===(c)
diff --git a/test/prism/fixtures/unparser/corpus/semantic/undef.txt b/test/prism/fixtures/unparser/corpus/semantic/undef.txt
new file mode 100644
index 0000000000..47debc3114
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/semantic/undef.txt
@@ -0,0 +1,2 @@
+undef foo
+undef foo, bar
diff --git a/test/prism/fixtures/unparser/corpus/semantic/while.txt b/test/prism/fixtures/unparser/corpus/semantic/while.txt
new file mode 100644
index 0000000000..a55dcc52fc
--- /dev/null
+++ b/test/prism/fixtures/unparser/corpus/semantic/while.txt
@@ -0,0 +1,25 @@
+a until b? {}
+
+until b? {}
+ a
+end
+
+foo = bar while foo
+
+a until b && a { }
+
+while a = b
+ a
+end
+
+a until b(<<-FOO) do
+FOO
+ c
+end
+
+module A
+ foo = exp
+ while foo
+ foo = bar
+ end
+end
diff --git a/test/prism/fixtures/until.txt b/test/prism/fixtures/until.txt
new file mode 100644
index 0000000000..652fc8c5a7
--- /dev/null
+++ b/test/prism/fixtures/until.txt
@@ -0,0 +1,13 @@
+until true; 1; end
+
+1 until true
+
+tap { break until true }
+
+tap { next until true }
+
+return until true
+
+foo :a, :b until bar?
+
+foo while bar in baz
diff --git a/test/prism/fixtures/variables.txt b/test/prism/fixtures/variables.txt
new file mode 100644
index 0000000000..4f4dc6f9c8
--- /dev/null
+++ b/test/prism/fixtures/variables.txt
@@ -0,0 +1,49 @@
+@@abc
+
+@@abc = 1
+
+@@foo, @@bar = 1
+
+@@foo = 1, 2
+
+$abc = 1
+
+$abc
+
+@abc
+
+@abc = 1
+
+a
+
+abc = 1
+
+$foo, $bar = 1
+
+$foo = 1, 2
+
+@foo, @bar = 1
+
+@foo = 1, 2
+
+foo = 1; foo = 1, 2
+
+foo = 1, 2
+
+foo, * = 1, 2
+
+foo, = 1, 2
+
+foo, *bar = 1, 2
+
+foo, (bar, baz) = 1, [2, 3]
+
+foo = *bar
+
+Foo = 1, 2
+
+(a; b; c)
+
+a, (b, c), d = []
+
+(a,), = []
diff --git a/test/prism/fixtures/while.txt b/test/prism/fixtures/while.txt
new file mode 100644
index 0000000000..b776f755ee
--- /dev/null
+++ b/test/prism/fixtures/while.txt
@@ -0,0 +1,23 @@
+while true; 1; end
+
+1 while true
+
+tap { break while true }
+
+tap { next while true }
+
+return while true
+
+foo :a, :b while bar?
+
+tap { while def self.foo a = tap do end; end; break; end }
+
+tap { while class Foo a = tap do end; end; break; end }
+
+tap { while class << self; tap do end; end; break; end }
+
+tap { while class << self; a = tap do end; end; break; end }
+
+while def foo = bar do end; end
+
+foo while bar in baz
diff --git a/test/prism/fixtures/whitequark/LICENSE b/test/prism/fixtures/whitequark/LICENSE
new file mode 100644
index 0000000000..43f9788985
--- /dev/null
+++ b/test/prism/fixtures/whitequark/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2013-2024 parser project contributors
+Copyright (c) 2013-2016 Catherine <whitequark@whitequark.org>
+
+Parts of the source are derived from ruby_parser:
+Copyright (c) Ryan Davis, seattle.rb
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/test/prism/fixtures/whitequark/__ENCODING__.txt b/test/prism/fixtures/whitequark/__ENCODING__.txt
new file mode 100644
index 0000000000..d6debf2f92
--- /dev/null
+++ b/test/prism/fixtures/whitequark/__ENCODING__.txt
@@ -0,0 +1 @@
+__ENCODING__
diff --git a/test/prism/fixtures/whitequark/__ENCODING___legacy_.txt b/test/prism/fixtures/whitequark/__ENCODING___legacy_.txt
new file mode 100644
index 0000000000..d6debf2f92
--- /dev/null
+++ b/test/prism/fixtures/whitequark/__ENCODING___legacy_.txt
@@ -0,0 +1 @@
+__ENCODING__
diff --git a/test/prism/fixtures/whitequark/alias.txt b/test/prism/fixtures/whitequark/alias.txt
new file mode 100644
index 0000000000..e33b120022
--- /dev/null
+++ b/test/prism/fixtures/whitequark/alias.txt
@@ -0,0 +1 @@
+alias :foo bar
diff --git a/test/prism/fixtures/whitequark/alias_gvar.txt b/test/prism/fixtures/whitequark/alias_gvar.txt
new file mode 100644
index 0000000000..b975d97f8e
--- /dev/null
+++ b/test/prism/fixtures/whitequark/alias_gvar.txt
@@ -0,0 +1,3 @@
+alias $a $+
+
+alias $a $b
diff --git a/test/prism/fixtures/whitequark/ambiuous_quoted_label_in_ternary_operator.txt b/test/prism/fixtures/whitequark/ambiuous_quoted_label_in_ternary_operator.txt
new file mode 100644
index 0000000000..9b2e3afad5
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ambiuous_quoted_label_in_ternary_operator.txt
@@ -0,0 +1 @@
+a ? b & '': nil
diff --git a/test/prism/fixtures/whitequark/and.txt b/test/prism/fixtures/whitequark/and.txt
new file mode 100644
index 0000000000..43fa6a65cd
--- /dev/null
+++ b/test/prism/fixtures/whitequark/and.txt
@@ -0,0 +1,3 @@
+foo && bar
+
+foo and bar
diff --git a/test/prism/fixtures/whitequark/and_asgn.txt b/test/prism/fixtures/whitequark/and_asgn.txt
new file mode 100644
index 0000000000..a979265914
--- /dev/null
+++ b/test/prism/fixtures/whitequark/and_asgn.txt
@@ -0,0 +1,3 @@
+foo.a &&= 1
+
+foo[0, 1] &&= 2
diff --git a/test/prism/fixtures/whitequark/and_or_masgn.txt b/test/prism/fixtures/whitequark/and_or_masgn.txt
new file mode 100644
index 0000000000..e346041604
--- /dev/null
+++ b/test/prism/fixtures/whitequark/and_or_masgn.txt
@@ -0,0 +1,3 @@
+foo && (a, b = bar)
+
+foo || (a, b = bar)
diff --git a/test/prism/fixtures/whitequark/anonymous_blockarg.txt b/test/prism/fixtures/whitequark/anonymous_blockarg.txt
new file mode 100644
index 0000000000..e3eaaad6ce
--- /dev/null
+++ b/test/prism/fixtures/whitequark/anonymous_blockarg.txt
@@ -0,0 +1 @@
+def foo(&); bar(&); end
diff --git a/test/prism/fixtures/whitequark/arg.txt b/test/prism/fixtures/whitequark/arg.txt
new file mode 100644
index 0000000000..b1984ad5c4
--- /dev/null
+++ b/test/prism/fixtures/whitequark/arg.txt
@@ -0,0 +1,3 @@
+def f(foo); end
+
+def f(foo, bar); end
diff --git a/test/prism/fixtures/whitequark/arg_combinations.txt b/test/prism/fixtures/whitequark/arg_combinations.txt
new file mode 100644
index 0000000000..801b1e47f4
--- /dev/null
+++ b/test/prism/fixtures/whitequark/arg_combinations.txt
@@ -0,0 +1,29 @@
+def f &b; end
+
+def f *r, &b; end
+
+def f *r, p, &b; end
+
+def f ; end
+
+def f a, &b; end
+
+def f a, *r, &b; end
+
+def f a, *r, p, &b; end
+
+def f a, o=1, &b; end
+
+def f a, o=1, *r, &b; end
+
+def f a, o=1, *r, p, &b; end
+
+def f a, o=1, p, &b; end
+
+def f o=1, &b; end
+
+def f o=1, *r, &b; end
+
+def f o=1, *r, p, &b; end
+
+def f o=1, p, &b; end
diff --git a/test/prism/fixtures/whitequark/arg_duplicate_ignored.txt b/test/prism/fixtures/whitequark/arg_duplicate_ignored.txt
new file mode 100644
index 0000000000..0f5cc33961
--- /dev/null
+++ b/test/prism/fixtures/whitequark/arg_duplicate_ignored.txt
@@ -0,0 +1,3 @@
+def foo(_, _); end
+
+def foo(_a, _a); end
diff --git a/test/prism/fixtures/whitequark/arg_label.txt b/test/prism/fixtures/whitequark/arg_label.txt
new file mode 100644
index 0000000000..82db416cb4
--- /dev/null
+++ b/test/prism/fixtures/whitequark/arg_label.txt
@@ -0,0 +1,6 @@
+def foo
+ a:b end
+
+def foo() a:b end
+
+f { || a:b }
diff --git a/test/prism/fixtures/whitequark/arg_scope.txt b/test/prism/fixtures/whitequark/arg_scope.txt
new file mode 100644
index 0000000000..6c67ab72e3
--- /dev/null
+++ b/test/prism/fixtures/whitequark/arg_scope.txt
@@ -0,0 +1 @@
+lambda{|;a|a}
diff --git a/test/prism/fixtures/whitequark/args.txt b/test/prism/fixtures/whitequark/args.txt
new file mode 100644
index 0000000000..773be477d3
--- /dev/null
+++ b/test/prism/fixtures/whitequark/args.txt
@@ -0,0 +1,63 @@
+def f &b; end
+
+def f (((a))); end
+
+def f ((*)); end
+
+def f ((*, p)); end
+
+def f ((*r)); end
+
+def f ((*r, p)); end
+
+def f ((a, *)); end
+
+def f ((a, *, p)); end
+
+def f ((a, *r)); end
+
+def f ((a, *r, p)); end
+
+def f ((a, a1)); end
+
+def f (foo: 1, &b); end
+
+def f (foo: 1, bar: 2, **baz, &b); end
+
+def f **baz, &b; end
+
+def f *, **; end
+
+def f *r, &b; end
+
+def f *r, p, &b; end
+
+def f ; end
+
+def f a, &b; end
+
+def f a, *r, &b; end
+
+def f a, *r, p, &b; end
+
+def f a, o=1, &b; end
+
+def f a, o=1, *r, &b; end
+
+def f a, o=1, *r, p, &b; end
+
+def f a, o=1, p, &b; end
+
+def f foo:
+; end
+
+def f foo: -1
+; end
+
+def f o=1, &b; end
+
+def f o=1, *r, &b; end
+
+def f o=1, *r, p, &b; end
+
+def f o=1, p, &b; end
diff --git a/test/prism/fixtures/whitequark/args_args_assocs.txt b/test/prism/fixtures/whitequark/args_args_assocs.txt
new file mode 100644
index 0000000000..445f899442
--- /dev/null
+++ b/test/prism/fixtures/whitequark/args_args_assocs.txt
@@ -0,0 +1,3 @@
+fun(foo, :foo => 1)
+
+fun(foo, :foo => 1, &baz)
diff --git a/test/prism/fixtures/whitequark/args_args_assocs_comma.txt b/test/prism/fixtures/whitequark/args_args_assocs_comma.txt
new file mode 100644
index 0000000000..b566a59037
--- /dev/null
+++ b/test/prism/fixtures/whitequark/args_args_assocs_comma.txt
@@ -0,0 +1 @@
+foo[bar, :baz => 1,]
diff --git a/test/prism/fixtures/whitequark/args_args_comma.txt b/test/prism/fixtures/whitequark/args_args_comma.txt
new file mode 100644
index 0000000000..80770716dd
--- /dev/null
+++ b/test/prism/fixtures/whitequark/args_args_comma.txt
@@ -0,0 +1 @@
+foo[bar,]
diff --git a/test/prism/fixtures/whitequark/args_args_star.txt b/test/prism/fixtures/whitequark/args_args_star.txt
new file mode 100644
index 0000000000..d4dc9cc579
--- /dev/null
+++ b/test/prism/fixtures/whitequark/args_args_star.txt
@@ -0,0 +1,3 @@
+fun(foo, *bar)
+
+fun(foo, *bar, &baz)
diff --git a/test/prism/fixtures/whitequark/args_assocs_comma.txt b/test/prism/fixtures/whitequark/args_assocs_comma.txt
new file mode 100644
index 0000000000..15e5cd65dc
--- /dev/null
+++ b/test/prism/fixtures/whitequark/args_assocs_comma.txt
@@ -0,0 +1 @@
+foo[:baz => 1,]
diff --git a/test/prism/fixtures/whitequark/args_block_pass.txt b/test/prism/fixtures/whitequark/args_block_pass.txt
new file mode 100644
index 0000000000..35d7d23885
--- /dev/null
+++ b/test/prism/fixtures/whitequark/args_block_pass.txt
@@ -0,0 +1 @@
+fun(&bar)
diff --git a/test/prism/fixtures/whitequark/args_cmd.txt b/test/prism/fixtures/whitequark/args_cmd.txt
new file mode 100644
index 0000000000..dd0c8891d0
--- /dev/null
+++ b/test/prism/fixtures/whitequark/args_cmd.txt
@@ -0,0 +1 @@
+fun(f bar)
diff --git a/test/prism/fixtures/whitequark/args_star.txt b/test/prism/fixtures/whitequark/args_star.txt
new file mode 100644
index 0000000000..ce1e6f8465
--- /dev/null
+++ b/test/prism/fixtures/whitequark/args_star.txt
@@ -0,0 +1,3 @@
+fun(*bar)
+
+fun(*bar, &baz)
diff --git a/test/prism/fixtures/whitequark/array_assocs.txt b/test/prism/fixtures/whitequark/array_assocs.txt
new file mode 100644
index 0000000000..fcecfcdefc
--- /dev/null
+++ b/test/prism/fixtures/whitequark/array_assocs.txt
@@ -0,0 +1,3 @@
+[ 1 => 2 ]
+
+[ 1, 2 => 3 ]
diff --git a/test/prism/fixtures/whitequark/array_plain.txt b/test/prism/fixtures/whitequark/array_plain.txt
new file mode 100644
index 0000000000..44e2ace7e5
--- /dev/null
+++ b/test/prism/fixtures/whitequark/array_plain.txt
@@ -0,0 +1 @@
+[1, 2]
diff --git a/test/prism/fixtures/whitequark/array_splat.txt b/test/prism/fixtures/whitequark/array_splat.txt
new file mode 100644
index 0000000000..144c1eb124
--- /dev/null
+++ b/test/prism/fixtures/whitequark/array_splat.txt
@@ -0,0 +1,5 @@
+[*foo]
+
+[1, *foo, 2]
+
+[1, *foo]
diff --git a/test/prism/fixtures/whitequark/array_symbols.txt b/test/prism/fixtures/whitequark/array_symbols.txt
new file mode 100644
index 0000000000..a9f9df0404
--- /dev/null
+++ b/test/prism/fixtures/whitequark/array_symbols.txt
@@ -0,0 +1 @@
+%i[foo bar]
diff --git a/test/prism/fixtures/whitequark/array_symbols_empty.txt b/test/prism/fixtures/whitequark/array_symbols_empty.txt
new file mode 100644
index 0000000000..da3a89ee9b
--- /dev/null
+++ b/test/prism/fixtures/whitequark/array_symbols_empty.txt
@@ -0,0 +1,3 @@
+%I()
+
+%i[]
diff --git a/test/prism/fixtures/whitequark/array_symbols_interp.txt b/test/prism/fixtures/whitequark/array_symbols_interp.txt
new file mode 100644
index 0000000000..d4950d0c05
--- /dev/null
+++ b/test/prism/fixtures/whitequark/array_symbols_interp.txt
@@ -0,0 +1,3 @@
+%I[foo #{bar}]
+
+%I[foo#{bar}]
diff --git a/test/prism/fixtures/whitequark/array_words.txt b/test/prism/fixtures/whitequark/array_words.txt
new file mode 100644
index 0000000000..a07380cadc
--- /dev/null
+++ b/test/prism/fixtures/whitequark/array_words.txt
@@ -0,0 +1 @@
+%w[foo bar]
diff --git a/test/prism/fixtures/whitequark/array_words_empty.txt b/test/prism/fixtures/whitequark/array_words_empty.txt
new file mode 100644
index 0000000000..7568263f4a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/array_words_empty.txt
@@ -0,0 +1,3 @@
+%W()
+
+%w[]
diff --git a/test/prism/fixtures/whitequark/array_words_interp.txt b/test/prism/fixtures/whitequark/array_words_interp.txt
new file mode 100644
index 0000000000..1460f7dc03
--- /dev/null
+++ b/test/prism/fixtures/whitequark/array_words_interp.txt
@@ -0,0 +1,3 @@
+%W[foo #{bar}]
+
+%W[foo #{bar}foo#@baz]
diff --git a/test/prism/fixtures/whitequark/asgn_cmd.txt b/test/prism/fixtures/whitequark/asgn_cmd.txt
new file mode 100644
index 0000000000..81f8cc1c8d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/asgn_cmd.txt
@@ -0,0 +1,3 @@
+foo = bar = m foo
+
+foo = m foo
diff --git a/test/prism/fixtures/whitequark/asgn_mrhs.txt b/test/prism/fixtures/whitequark/asgn_mrhs.txt
new file mode 100644
index 0000000000..f0b0055e55
--- /dev/null
+++ b/test/prism/fixtures/whitequark/asgn_mrhs.txt
@@ -0,0 +1,5 @@
+foo = *bar
+
+foo = bar, 1
+
+foo = baz, *bar
diff --git a/test/prism/fixtures/whitequark/back_ref.txt b/test/prism/fixtures/whitequark/back_ref.txt
new file mode 100644
index 0000000000..03166e10ee
--- /dev/null
+++ b/test/prism/fixtures/whitequark/back_ref.txt
@@ -0,0 +1 @@
+$+
diff --git a/test/prism/fixtures/whitequark/bang.txt b/test/prism/fixtures/whitequark/bang.txt
new file mode 100644
index 0000000000..6cf9410cf5
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bang.txt
@@ -0,0 +1 @@
+!foo
diff --git a/test/prism/fixtures/whitequark/bang_cmd.txt b/test/prism/fixtures/whitequark/bang_cmd.txt
new file mode 100644
index 0000000000..0a5252c001
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bang_cmd.txt
@@ -0,0 +1 @@
+!m foo
diff --git a/test/prism/fixtures/whitequark/begin_cmdarg.txt b/test/prism/fixtures/whitequark/begin_cmdarg.txt
new file mode 100644
index 0000000000..a5873668e9
--- /dev/null
+++ b/test/prism/fixtures/whitequark/begin_cmdarg.txt
@@ -0,0 +1 @@
+p begin 1.times do 1 end end
diff --git a/test/prism/fixtures/whitequark/beginless_erange_after_newline.txt b/test/prism/fixtures/whitequark/beginless_erange_after_newline.txt
new file mode 100644
index 0000000000..ae6c75564a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/beginless_erange_after_newline.txt
@@ -0,0 +1,2 @@
+foo
+...100
diff --git a/test/prism/fixtures/whitequark/beginless_irange_after_newline.txt b/test/prism/fixtures/whitequark/beginless_irange_after_newline.txt
new file mode 100644
index 0000000000..bfc8d5e5e8
--- /dev/null
+++ b/test/prism/fixtures/whitequark/beginless_irange_after_newline.txt
@@ -0,0 +1,2 @@
+foo
+..100
diff --git a/test/prism/fixtures/whitequark/beginless_range.txt b/test/prism/fixtures/whitequark/beginless_range.txt
new file mode 100644
index 0000000000..ef52703b8a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/beginless_range.txt
@@ -0,0 +1,3 @@
+...100
+
+..100
diff --git a/test/prism/fixtures/whitequark/block_arg_combinations.txt b/test/prism/fixtures/whitequark/block_arg_combinations.txt
new file mode 100644
index 0000000000..ccb9cfea56
--- /dev/null
+++ b/test/prism/fixtures/whitequark/block_arg_combinations.txt
@@ -0,0 +1,57 @@
+f{ }
+
+f{ | | }
+
+f{ |&b| }
+
+f{ |*, &b| }
+
+f{ |*r, p, &b| }
+
+f{ |*s, &b| }
+
+f{ |*s| }
+
+f{ |*| }
+
+f{ |;
+a
+| }
+
+f{ |;a| }
+
+f{ |a, &b| }
+
+f{ |a, *, &b| }
+
+f{ |a, *r, p, &b| }
+
+f{ |a, *s, &b| }
+
+f{ |a, *s| }
+
+f{ |a, *| }
+
+f{ |a, c| }
+
+f{ |a, o=1, &b| }
+
+f{ |a, o=1, *r, p, &b| }
+
+f{ |a, o=1, o1=2, *r, &b| }
+
+f{ |a, o=1, p, &b| }
+
+f{ |a,| }
+
+f{ |a| }
+
+f{ |o=1, &b| }
+
+f{ |o=1, *r, &b| }
+
+f{ |o=1, *r, p, &b| }
+
+f{ |o=1, p, &b| }
+
+f{ || }
diff --git a/test/prism/fixtures/whitequark/block_kwarg.txt b/test/prism/fixtures/whitequark/block_kwarg.txt
new file mode 100644
index 0000000000..9f1283371f
--- /dev/null
+++ b/test/prism/fixtures/whitequark/block_kwarg.txt
@@ -0,0 +1 @@
+f{ |foo:| }
diff --git a/test/prism/fixtures/whitequark/block_kwarg_combinations.txt b/test/prism/fixtures/whitequark/block_kwarg_combinations.txt
new file mode 100644
index 0000000000..3dbb961777
--- /dev/null
+++ b/test/prism/fixtures/whitequark/block_kwarg_combinations.txt
@@ -0,0 +1,5 @@
+f{ |**baz, &b| }
+
+f{ |foo: 1, &b| }
+
+f{ |foo: 1, bar: 2, **baz, &b| }
diff --git a/test/prism/fixtures/whitequark/blockarg.txt b/test/prism/fixtures/whitequark/blockarg.txt
new file mode 100644
index 0000000000..63552e97be
--- /dev/null
+++ b/test/prism/fixtures/whitequark/blockarg.txt
@@ -0,0 +1 @@
+def f(&block); end
diff --git a/test/prism/fixtures/whitequark/blockargs.txt b/test/prism/fixtures/whitequark/blockargs.txt
new file mode 100644
index 0000000000..cdd2c4f331
--- /dev/null
+++ b/test/prism/fixtures/whitequark/blockargs.txt
@@ -0,0 +1,71 @@
+f{ }
+
+f{ | | }
+
+f{ |&b| }
+
+f{ |**baz, &b| }
+
+f{ |*, &b| }
+
+f{ |*r, p, &b| }
+
+f{ |*s, &b| }
+
+f{ |*s| }
+
+f{ |*| }
+
+f{ |;
+a
+| }
+
+f{ |;a| }
+
+f{ |a, &b| }
+
+f{ |a, *, &b| }
+
+f{ |a, *r, p, &b| }
+
+f{ |a, *s, &b| }
+
+f{ |a, *s| }
+
+f{ |a, *| }
+
+f{ |a, b,| }
+
+f{ |a, c| }
+
+f{ |a, o=1, &b| }
+
+f{ |a, o=1, *r, p, &b| }
+
+f{ |a, o=1, o1=2, *r, &b| }
+
+f{ |a, o=1, p, &b| }
+
+f{ |a,| }
+
+f{ |a| }
+
+f{ |a| }
+
+f{ |a| }
+
+f{ |foo: 1, &b| }
+
+f{ |foo: 1, bar: 2, **baz, &b| }
+
+f{ |foo:| }
+
+f{ |o=1, &b| }
+
+f{ |o=1, *r, &b| }
+
+f{ |o=1, *r, p, &b| }
+
+f{ |o=1, p, &b| }
+
+f{ || }
diff --git a/test/prism/fixtures/whitequark/bug_435.txt b/test/prism/fixtures/whitequark/bug_435.txt
new file mode 100644
index 0000000000..3e4e0d5abd
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_435.txt
@@ -0,0 +1 @@
+"#{-> foo {}}"
diff --git a/test/prism/fixtures/whitequark/bug_447.txt b/test/prism/fixtures/whitequark/bug_447.txt
new file mode 100644
index 0000000000..7da59bbc2f
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_447.txt
@@ -0,0 +1,3 @@
+m [] do end
+
+m [], 1 do end
diff --git a/test/prism/fixtures/whitequark/bug_452.txt b/test/prism/fixtures/whitequark/bug_452.txt
new file mode 100644
index 0000000000..8b41dd6027
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_452.txt
@@ -0,0 +1 @@
+td (1_500).toString(); td.num do; end
diff --git a/test/prism/fixtures/whitequark/bug_466.txt b/test/prism/fixtures/whitequark/bug_466.txt
new file mode 100644
index 0000000000..ad02ad38ae
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_466.txt
@@ -0,0 +1 @@
+foo "#{(1+1).to_i}" do; end
diff --git a/test/prism/fixtures/whitequark/bug_473.txt b/test/prism/fixtures/whitequark/bug_473.txt
new file mode 100644
index 0000000000..0d2ea883a1
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_473.txt
@@ -0,0 +1 @@
+m "#{[]}"
diff --git a/test/prism/fixtures/whitequark/bug_480.txt b/test/prism/fixtures/whitequark/bug_480.txt
new file mode 100644
index 0000000000..0558b2c957
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_480.txt
@@ -0,0 +1 @@
+m "#{}#{()}"
diff --git a/test/prism/fixtures/whitequark/bug_481.txt b/test/prism/fixtures/whitequark/bug_481.txt
new file mode 100644
index 0000000000..6328e9dbbd
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_481.txt
@@ -0,0 +1 @@
+m def x(); end; 1.tap do end
diff --git a/test/prism/fixtures/whitequark/bug_ascii_8bit_in_literal.txt b/test/prism/fixtures/whitequark/bug_ascii_8bit_in_literal.txt
new file mode 100644
index 0000000000..85399bd19a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_ascii_8bit_in_literal.txt
@@ -0,0 +1,2 @@
+# coding:utf-8
+ "\xD0\xBF\xD1\x80\xD0\xBE\xD0\xB2\xD0\xB5\xD1\x80\xD0\xBA\xD0\xB0"
diff --git a/test/prism/fixtures/whitequark/bug_cmd_string_lookahead.txt b/test/prism/fixtures/whitequark/bug_cmd_string_lookahead.txt
new file mode 100644
index 0000000000..7e9e54c518
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_cmd_string_lookahead.txt
@@ -0,0 +1 @@
+desc "foo" do end
diff --git a/test/prism/fixtures/whitequark/bug_cmdarg.txt b/test/prism/fixtures/whitequark/bug_cmdarg.txt
new file mode 100644
index 0000000000..0281cd6668
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_cmdarg.txt
@@ -0,0 +1,5 @@
+assert do: true
+
+assert dogs
+
+f x: -> do meth do end end
diff --git a/test/prism/fixtures/whitequark/bug_def_no_paren_eql_begin.txt b/test/prism/fixtures/whitequark/bug_def_no_paren_eql_begin.txt
new file mode 100644
index 0000000000..615dc88217
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_def_no_paren_eql_begin.txt
@@ -0,0 +1,4 @@
+def foo
+=begin
+=end
+end
diff --git a/test/prism/fixtures/whitequark/bug_do_block_in_call_args.txt b/test/prism/fixtures/whitequark/bug_do_block_in_call_args.txt
new file mode 100644
index 0000000000..21340fd6e8
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_do_block_in_call_args.txt
@@ -0,0 +1 @@
+bar def foo; self.each do end end
diff --git a/test/prism/fixtures/whitequark/bug_do_block_in_cmdarg.txt b/test/prism/fixtures/whitequark/bug_do_block_in_cmdarg.txt
new file mode 100644
index 0000000000..7dece50408
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_do_block_in_cmdarg.txt
@@ -0,0 +1 @@
+tap (proc do end)
diff --git a/test/prism/fixtures/whitequark/bug_do_block_in_hash_brace.txt b/test/prism/fixtures/whitequark/bug_do_block_in_hash_brace.txt
new file mode 100644
index 0000000000..6c4dd205d2
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_do_block_in_hash_brace.txt
@@ -0,0 +1,9 @@
+p :foo, {"a": proc do end, b: proc do end}
+
+p :foo, {** proc do end, b: proc do end}
+
+p :foo, {:a => proc do end, b: proc do end}
+
+p :foo, {a: proc do end, b: proc do end}
+
+p :foo, {proc do end => proc do end, b: proc do end}
diff --git a/test/prism/fixtures/whitequark/bug_heredoc_do.txt b/test/prism/fixtures/whitequark/bug_heredoc_do.txt
new file mode 100644
index 0000000000..06fef0a99f
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_heredoc_do.txt
@@ -0,0 +1,3 @@
+f <<-TABLE do
+TABLE
+end
diff --git a/test/prism/fixtures/whitequark/bug_interp_single.txt b/test/prism/fixtures/whitequark/bug_interp_single.txt
new file mode 100644
index 0000000000..be0b1a8542
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_interp_single.txt
@@ -0,0 +1,3 @@
+"#{1}"
+
+%W"#{1}"
diff --git a/test/prism/fixtures/whitequark/bug_lambda_leakage.txt b/test/prism/fixtures/whitequark/bug_lambda_leakage.txt
new file mode 100644
index 0000000000..372b36929a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_lambda_leakage.txt
@@ -0,0 +1 @@
+->(scope) {}; scope
diff --git a/test/prism/fixtures/whitequark/bug_regex_verification.txt b/test/prism/fixtures/whitequark/bug_regex_verification.txt
new file mode 100644
index 0000000000..f8483c8b10
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_regex_verification.txt
@@ -0,0 +1 @@
+/#)/x
diff --git a/test/prism/fixtures/whitequark/bug_rescue_empty_else.txt b/test/prism/fixtures/whitequark/bug_rescue_empty_else.txt
new file mode 100644
index 0000000000..e8c81edc57
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_rescue_empty_else.txt
@@ -0,0 +1 @@
+begin; rescue LoadError; else; end
diff --git a/test/prism/fixtures/whitequark/bug_while_not_parens_do.txt b/test/prism/fixtures/whitequark/bug_while_not_parens_do.txt
new file mode 100644
index 0000000000..628c36ef13
--- /dev/null
+++ b/test/prism/fixtures/whitequark/bug_while_not_parens_do.txt
@@ -0,0 +1 @@
+while not (true) do end
diff --git a/test/prism/fixtures/whitequark/case_cond.txt b/test/prism/fixtures/whitequark/case_cond.txt
new file mode 100644
index 0000000000..a236b27ebd
--- /dev/null
+++ b/test/prism/fixtures/whitequark/case_cond.txt
@@ -0,0 +1 @@
+case; when foo; 'foo'; end
diff --git a/test/prism/fixtures/whitequark/case_cond_else.txt b/test/prism/fixtures/whitequark/case_cond_else.txt
new file mode 100644
index 0000000000..06eefa4a1b
--- /dev/null
+++ b/test/prism/fixtures/whitequark/case_cond_else.txt
@@ -0,0 +1 @@
+case; when foo; 'foo'; else 'bar'; end
diff --git a/test/prism/fixtures/whitequark/case_expr.txt b/test/prism/fixtures/whitequark/case_expr.txt
new file mode 100644
index 0000000000..472672c781
--- /dev/null
+++ b/test/prism/fixtures/whitequark/case_expr.txt
@@ -0,0 +1 @@
+case foo; when 'bar'; bar; end
diff --git a/test/prism/fixtures/whitequark/case_expr_else.txt b/test/prism/fixtures/whitequark/case_expr_else.txt
new file mode 100644
index 0000000000..3c55826134
--- /dev/null
+++ b/test/prism/fixtures/whitequark/case_expr_else.txt
@@ -0,0 +1 @@
+case foo; when 'bar'; bar; else baz; end
diff --git a/test/prism/fixtures/whitequark/casgn_scoped.txt b/test/prism/fixtures/whitequark/casgn_scoped.txt
new file mode 100644
index 0000000000..964d0f4c9b
--- /dev/null
+++ b/test/prism/fixtures/whitequark/casgn_scoped.txt
@@ -0,0 +1 @@
+Bar::Foo = 10
diff --git a/test/prism/fixtures/whitequark/casgn_toplevel.txt b/test/prism/fixtures/whitequark/casgn_toplevel.txt
new file mode 100644
index 0000000000..047a3b6745
--- /dev/null
+++ b/test/prism/fixtures/whitequark/casgn_toplevel.txt
@@ -0,0 +1 @@
+::Foo = 10
diff --git a/test/prism/fixtures/whitequark/casgn_unscoped.txt b/test/prism/fixtures/whitequark/casgn_unscoped.txt
new file mode 100644
index 0000000000..5632cf64ee
--- /dev/null
+++ b/test/prism/fixtures/whitequark/casgn_unscoped.txt
@@ -0,0 +1 @@
+Foo = 10
diff --git a/test/prism/fixtures/whitequark/character.txt b/test/prism/fixtures/whitequark/character.txt
new file mode 100644
index 0000000000..b22ffbb71a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/character.txt
@@ -0,0 +1 @@
+?a
diff --git a/test/prism/fixtures/whitequark/class.txt b/test/prism/fixtures/whitequark/class.txt
new file mode 100644
index 0000000000..a30a248e96
--- /dev/null
+++ b/test/prism/fixtures/whitequark/class.txt
@@ -0,0 +1,3 @@
+class Foo end
+
+class Foo; end
diff --git a/test/prism/fixtures/whitequark/class_super.txt b/test/prism/fixtures/whitequark/class_super.txt
new file mode 100644
index 0000000000..8829d82d36
--- /dev/null
+++ b/test/prism/fixtures/whitequark/class_super.txt
@@ -0,0 +1 @@
+class Foo < Bar; end
diff --git a/test/prism/fixtures/whitequark/class_super_label.txt b/test/prism/fixtures/whitequark/class_super_label.txt
new file mode 100644
index 0000000000..5d47897ab6
--- /dev/null
+++ b/test/prism/fixtures/whitequark/class_super_label.txt
@@ -0,0 +1 @@
+class Foo < a:b; end
diff --git a/test/prism/fixtures/whitequark/comments_before_leading_dot__27.txt b/test/prism/fixtures/whitequark/comments_before_leading_dot__27.txt
new file mode 100644
index 0000000000..208f2d87fe
--- /dev/null
+++ b/test/prism/fixtures/whitequark/comments_before_leading_dot__27.txt
@@ -0,0 +1,19 @@
+a #
+ #
+&.foo
+
+
+a #
+ #
+.foo
+
+
+a #
+#
+&.foo
+
+
+a #
+#
+.foo
+
diff --git a/test/prism/fixtures/whitequark/complex.txt b/test/prism/fixtures/whitequark/complex.txt
new file mode 100644
index 0000000000..1dbf2c13f4
--- /dev/null
+++ b/test/prism/fixtures/whitequark/complex.txt
@@ -0,0 +1,7 @@
+42.1i
+
+42.1ri
+
+42i
+
+42ri
diff --git a/test/prism/fixtures/whitequark/cond_begin.txt b/test/prism/fixtures/whitequark/cond_begin.txt
new file mode 100644
index 0000000000..49d709b79c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/cond_begin.txt
@@ -0,0 +1 @@
+if (bar); foo; end
diff --git a/test/prism/fixtures/whitequark/cond_begin_masgn.txt b/test/prism/fixtures/whitequark/cond_begin_masgn.txt
new file mode 100644
index 0000000000..f9b65026b4
--- /dev/null
+++ b/test/prism/fixtures/whitequark/cond_begin_masgn.txt
@@ -0,0 +1 @@
+if (bar; a, b = foo); end
diff --git a/test/prism/fixtures/whitequark/cond_eflipflop.txt b/test/prism/fixtures/whitequark/cond_eflipflop.txt
new file mode 100644
index 0000000000..1236c2dbb5
--- /dev/null
+++ b/test/prism/fixtures/whitequark/cond_eflipflop.txt
@@ -0,0 +1,3 @@
+!(foo...bar)
+
+if foo...bar; end
diff --git a/test/prism/fixtures/whitequark/cond_eflipflop_with_beginless_range.txt b/test/prism/fixtures/whitequark/cond_eflipflop_with_beginless_range.txt
new file mode 100644
index 0000000000..757863b12b
--- /dev/null
+++ b/test/prism/fixtures/whitequark/cond_eflipflop_with_beginless_range.txt
@@ -0,0 +1 @@
+if ...bar; end
diff --git a/test/prism/fixtures/whitequark/cond_eflipflop_with_endless_range.txt b/test/prism/fixtures/whitequark/cond_eflipflop_with_endless_range.txt
new file mode 100644
index 0000000000..8a3b815ec9
--- /dev/null
+++ b/test/prism/fixtures/whitequark/cond_eflipflop_with_endless_range.txt
@@ -0,0 +1 @@
+if foo...; end
diff --git a/test/prism/fixtures/whitequark/cond_iflipflop.txt b/test/prism/fixtures/whitequark/cond_iflipflop.txt
new file mode 100644
index 0000000000..84bee71a74
--- /dev/null
+++ b/test/prism/fixtures/whitequark/cond_iflipflop.txt
@@ -0,0 +1,3 @@
+!(foo..bar)
+
+if foo..bar; end
diff --git a/test/prism/fixtures/whitequark/cond_iflipflop_with_beginless_range.txt b/test/prism/fixtures/whitequark/cond_iflipflop_with_beginless_range.txt
new file mode 100644
index 0000000000..4ff5b09690
--- /dev/null
+++ b/test/prism/fixtures/whitequark/cond_iflipflop_with_beginless_range.txt
@@ -0,0 +1 @@
+if ..bar; end
diff --git a/test/prism/fixtures/whitequark/cond_iflipflop_with_endless_range.txt b/test/prism/fixtures/whitequark/cond_iflipflop_with_endless_range.txt
new file mode 100644
index 0000000000..2739ad0e2a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/cond_iflipflop_with_endless_range.txt
@@ -0,0 +1 @@
+if foo..; end
diff --git a/test/prism/fixtures/whitequark/cond_match_current_line.txt b/test/prism/fixtures/whitequark/cond_match_current_line.txt
new file mode 100644
index 0000000000..21878c7bd8
--- /dev/null
+++ b/test/prism/fixtures/whitequark/cond_match_current_line.txt
@@ -0,0 +1,3 @@
+!/wat/
+
+if /wat/; end
diff --git a/test/prism/fixtures/whitequark/const_op_asgn.txt b/test/prism/fixtures/whitequark/const_op_asgn.txt
new file mode 100644
index 0000000000..e72e7adee8
--- /dev/null
+++ b/test/prism/fixtures/whitequark/const_op_asgn.txt
@@ -0,0 +1,9 @@
+::A += 1
+
+A += 1
+
+B::A += 1
+
+def x; ::A ||= 1; end
+
+def x; self::A ||= 1; end
diff --git a/test/prism/fixtures/whitequark/const_scoped.txt b/test/prism/fixtures/whitequark/const_scoped.txt
new file mode 100644
index 0000000000..4b03d85fc0
--- /dev/null
+++ b/test/prism/fixtures/whitequark/const_scoped.txt
@@ -0,0 +1 @@
+Bar::Foo
diff --git a/test/prism/fixtures/whitequark/const_toplevel.txt b/test/prism/fixtures/whitequark/const_toplevel.txt
new file mode 100644
index 0000000000..f783ae752b
--- /dev/null
+++ b/test/prism/fixtures/whitequark/const_toplevel.txt
@@ -0,0 +1 @@
+::Foo
diff --git a/test/prism/fixtures/whitequark/const_unscoped.txt b/test/prism/fixtures/whitequark/const_unscoped.txt
new file mode 100644
index 0000000000..bc56c4d894
--- /dev/null
+++ b/test/prism/fixtures/whitequark/const_unscoped.txt
@@ -0,0 +1 @@
+Foo
diff --git a/test/prism/fixtures/whitequark/cpath.txt b/test/prism/fixtures/whitequark/cpath.txt
new file mode 100644
index 0000000000..a4041692d1
--- /dev/null
+++ b/test/prism/fixtures/whitequark/cpath.txt
@@ -0,0 +1,3 @@
+module ::Foo; end
+
+module Bar::Foo; end
diff --git a/test/prism/fixtures/whitequark/cvar.txt b/test/prism/fixtures/whitequark/cvar.txt
new file mode 100644
index 0000000000..4997896e4a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/cvar.txt
@@ -0,0 +1 @@
+@@foo
diff --git a/test/prism/fixtures/whitequark/cvasgn.txt b/test/prism/fixtures/whitequark/cvasgn.txt
new file mode 100644
index 0000000000..8f7e19c4fe
--- /dev/null
+++ b/test/prism/fixtures/whitequark/cvasgn.txt
@@ -0,0 +1 @@
+@@var = 10
diff --git a/test/prism/fixtures/whitequark/dedenting_heredoc.txt b/test/prism/fixtures/whitequark/dedenting_heredoc.txt
new file mode 100644
index 0000000000..84937d84ab
--- /dev/null
+++ b/test/prism/fixtures/whitequark/dedenting_heredoc.txt
@@ -0,0 +1,75 @@
+p <<~"E"
+ x
+ #{" y"}
+E
+
+p <<~"E"
+ x
+ #{foo}
+E
+
+p <<~E
+ x
+ y
+E
+
+p <<~E
+ x
+ y
+E
+
+p <<~E
+ x
+ y
+E
+
+p <<~E
+ x
+ y
+E
+
+p <<~E
+ x
+ \ y
+E
+
+p <<~E
+ x
+ \ y
+E
+
+p <<~E
+ E
+
+p <<~E
+ x
+
+y
+E
+
+p <<~E
+ x
+
+ y
+E
+
+p <<~E
+ x
+ y
+E
+
+p <<~E
+ x
+E
+
+p <<~E
+ ð
+E
+
+p <<~E
+E
+
+p <<~`E`
+ x
+ #{foo}
+E
diff --git a/test/prism/fixtures/whitequark/dedenting_interpolating_heredoc_fake_line_continuation.txt b/test/prism/fixtures/whitequark/dedenting_interpolating_heredoc_fake_line_continuation.txt
new file mode 100644
index 0000000000..0427715d61
--- /dev/null
+++ b/test/prism/fixtures/whitequark/dedenting_interpolating_heredoc_fake_line_continuation.txt
@@ -0,0 +1,4 @@
+<<~'FOO'
+ baz\\
+ qux
+FOO
diff --git a/test/prism/fixtures/whitequark/dedenting_non_interpolating_heredoc_line_continuation.txt b/test/prism/fixtures/whitequark/dedenting_non_interpolating_heredoc_line_continuation.txt
new file mode 100644
index 0000000000..fd7bc02419
--- /dev/null
+++ b/test/prism/fixtures/whitequark/dedenting_non_interpolating_heredoc_line_continuation.txt
@@ -0,0 +1,4 @@
+<<~'FOO'
+ baz\
+ qux
+FOO
diff --git a/test/prism/fixtures/whitequark/def.txt b/test/prism/fixtures/whitequark/def.txt
new file mode 100644
index 0000000000..d96a4238b3
--- /dev/null
+++ b/test/prism/fixtures/whitequark/def.txt
@@ -0,0 +1,11 @@
+def BEGIN; end
+
+def END; end
+
+def String; end
+
+def String=; end
+
+def foo; end
+
+def until; end
diff --git a/test/prism/fixtures/whitequark/defined.txt b/test/prism/fixtures/whitequark/defined.txt
new file mode 100644
index 0000000000..5cf93e22e3
--- /dev/null
+++ b/test/prism/fixtures/whitequark/defined.txt
@@ -0,0 +1,5 @@
+defined? @foo
+
+defined? foo
+
+defined?(foo)
diff --git a/test/prism/fixtures/whitequark/defs.txt b/test/prism/fixtures/whitequark/defs.txt
new file mode 100644
index 0000000000..e0b7aa86eb
--- /dev/null
+++ b/test/prism/fixtures/whitequark/defs.txt
@@ -0,0 +1,9 @@
+def (foo).foo; end
+
+def String.foo; end
+
+def String::foo; end
+
+def self.foo; end
+
+def self::foo; end
diff --git a/test/prism/fixtures/whitequark/emit_arg_inside_procarg0_legacy.txt b/test/prism/fixtures/whitequark/emit_arg_inside_procarg0_legacy.txt
new file mode 100644
index 0000000000..a985f15b6e
--- /dev/null
+++ b/test/prism/fixtures/whitequark/emit_arg_inside_procarg0_legacy.txt
@@ -0,0 +1 @@
+f{ |a| }
diff --git a/test/prism/fixtures/whitequark/empty_stmt.txt b/test/prism/fixtures/whitequark/empty_stmt.txt
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/test/prism/fixtures/whitequark/empty_stmt.txt
@@ -0,0 +1 @@
+
diff --git a/test/prism/fixtures/whitequark/endless_comparison_method.txt b/test/prism/fixtures/whitequark/endless_comparison_method.txt
new file mode 100644
index 0000000000..e10c3a6ced
--- /dev/null
+++ b/test/prism/fixtures/whitequark/endless_comparison_method.txt
@@ -0,0 +1,11 @@
+def !=(other) = do_something
+
+def !=(other) = do_something
+
+def <=(other) = do_something
+
+def ==(other) = do_something
+
+def ===(other) = do_something
+
+def >=(other) = do_something
diff --git a/test/prism/fixtures/whitequark/endless_method.txt b/test/prism/fixtures/whitequark/endless_method.txt
new file mode 100644
index 0000000000..7002526229
--- /dev/null
+++ b/test/prism/fixtures/whitequark/endless_method.txt
@@ -0,0 +1,7 @@
+def foo() = 42
+
+def inc(x) = x + 1
+
+def obj.foo() = 42
+
+def obj.inc(x) = x + 1
diff --git a/test/prism/fixtures/whitequark/endless_method_command_syntax.txt b/test/prism/fixtures/whitequark/endless_method_command_syntax.txt
new file mode 100644
index 0000000000..d9dad2d747
--- /dev/null
+++ b/test/prism/fixtures/whitequark/endless_method_command_syntax.txt
@@ -0,0 +1,15 @@
+def foo = puts "Hello"
+
+def foo() = puts "Hello"
+
+def foo(x) = puts x
+
+def obj.foo = puts "Hello"
+
+def obj.foo() = puts "Hello"
+
+def obj.foo(x) = puts x
+
+def rescued(x) = raise "to be caught" rescue "instance #{x}"
+
+def self.rescued(x) = raise "to be caught" rescue "class #{x}"
diff --git a/test/prism/fixtures/whitequark/endless_method_forwarded_args_legacy.txt b/test/prism/fixtures/whitequark/endless_method_forwarded_args_legacy.txt
new file mode 100644
index 0000000000..5955e40b5b
--- /dev/null
+++ b/test/prism/fixtures/whitequark/endless_method_forwarded_args_legacy.txt
@@ -0,0 +1 @@
+def foo(...) = bar(...)
diff --git a/test/prism/fixtures/whitequark/endless_method_with_rescue_mod.txt b/test/prism/fixtures/whitequark/endless_method_with_rescue_mod.txt
new file mode 100644
index 0000000000..93dc63a45d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/endless_method_with_rescue_mod.txt
@@ -0,0 +1,3 @@
+def m() = 1 rescue 2
+
+def self.m() = 1 rescue 2
diff --git a/test/prism/fixtures/whitequark/endless_method_without_args.txt b/test/prism/fixtures/whitequark/endless_method_without_args.txt
new file mode 100644
index 0000000000..90ea8f7c6d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/endless_method_without_args.txt
@@ -0,0 +1,7 @@
+def foo = 42
+
+def foo = 42 rescue nil
+
+def self.foo = 42
+
+def self.foo = 42 rescue nil
diff --git a/test/prism/fixtures/whitequark/ensure.txt b/test/prism/fixtures/whitequark/ensure.txt
new file mode 100644
index 0000000000..6c4b47c63c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ensure.txt
@@ -0,0 +1 @@
+begin; meth; ensure; bar; end
diff --git a/test/prism/fixtures/whitequark/ensure_empty.txt b/test/prism/fixtures/whitequark/ensure_empty.txt
new file mode 100644
index 0000000000..39a175c371
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ensure_empty.txt
@@ -0,0 +1 @@
+begin ensure end
diff --git a/test/prism/fixtures/whitequark/false.txt b/test/prism/fixtures/whitequark/false.txt
new file mode 100644
index 0000000000..c508d5366f
--- /dev/null
+++ b/test/prism/fixtures/whitequark/false.txt
@@ -0,0 +1 @@
+false
diff --git a/test/prism/fixtures/whitequark/find_pattern.txt b/test/prism/fixtures/whitequark/find_pattern.txt
new file mode 100644
index 0000000000..fb8999ae28
--- /dev/null
+++ b/test/prism/fixtures/whitequark/find_pattern.txt
@@ -0,0 +1,7 @@
+case foo; in *, 42, * then true; end
+
+case foo; in Array[*, 1, *] then true; end
+
+case foo; in String(*, 1, *) then true; end
+
+case foo; in [*x, 1 => a, *y] then true; end
diff --git a/test/prism/fixtures/whitequark/float.txt b/test/prism/fixtures/whitequark/float.txt
new file mode 100644
index 0000000000..8c7592a192
--- /dev/null
+++ b/test/prism/fixtures/whitequark/float.txt
@@ -0,0 +1,3 @@
+-1.33
+
+1.33
diff --git a/test/prism/fixtures/whitequark/for.txt b/test/prism/fixtures/whitequark/for.txt
new file mode 100644
index 0000000000..a27ae578da
--- /dev/null
+++ b/test/prism/fixtures/whitequark/for.txt
@@ -0,0 +1,3 @@
+for a in foo do p a; end
+
+for a in foo; p a; end
diff --git a/test/prism/fixtures/whitequark/for_mlhs.txt b/test/prism/fixtures/whitequark/for_mlhs.txt
new file mode 100644
index 0000000000..53cd5229a4
--- /dev/null
+++ b/test/prism/fixtures/whitequark/for_mlhs.txt
@@ -0,0 +1 @@
+for a, b in foo; p a, b; end
diff --git a/test/prism/fixtures/whitequark/forward_arg.txt b/test/prism/fixtures/whitequark/forward_arg.txt
new file mode 100644
index 0000000000..c7590a8d53
--- /dev/null
+++ b/test/prism/fixtures/whitequark/forward_arg.txt
@@ -0,0 +1 @@
+def foo(...); bar(...); end
diff --git a/test/prism/fixtures/whitequark/forward_arg_with_open_args.txt b/test/prism/fixtures/whitequark/forward_arg_with_open_args.txt
new file mode 100644
index 0000000000..fd4c06bcb5
--- /dev/null
+++ b/test/prism/fixtures/whitequark/forward_arg_with_open_args.txt
@@ -0,0 +1,27 @@
+(def foo ...
+ bar(...)
+end)
+
+(def foo ...; bar(...); end)
+
+def foo ...
+end
+
+def foo ...; bar(...); end
+
+def foo a, ...
+ bar(...)
+end
+
+def foo a, ...; bar(...); end
+
+def foo a, b = 1, ...
+end
+
+def foo b = 1, ...
+ bar(...)
+end
+
+def foo b = 1, ...; bar(...); end
+
+def foo(a, ...) bar(...) end
diff --git a/test/prism/fixtures/whitequark/forward_args_legacy.txt b/test/prism/fixtures/whitequark/forward_args_legacy.txt
new file mode 100644
index 0000000000..0d9162457f
--- /dev/null
+++ b/test/prism/fixtures/whitequark/forward_args_legacy.txt
@@ -0,0 +1,5 @@
+def foo(...); bar(...); end
+
+def foo(...); end
+
+def foo(...); super(...); end
diff --git a/test/prism/fixtures/whitequark/forwarded_argument_with_kwrestarg.txt b/test/prism/fixtures/whitequark/forwarded_argument_with_kwrestarg.txt
new file mode 100644
index 0000000000..7dbf472232
--- /dev/null
+++ b/test/prism/fixtures/whitequark/forwarded_argument_with_kwrestarg.txt
@@ -0,0 +1 @@
+def foo(argument, **); bar(argument, **); end
diff --git a/test/prism/fixtures/whitequark/forwarded_argument_with_restarg.txt b/test/prism/fixtures/whitequark/forwarded_argument_with_restarg.txt
new file mode 100644
index 0000000000..f734bfd9ec
--- /dev/null
+++ b/test/prism/fixtures/whitequark/forwarded_argument_with_restarg.txt
@@ -0,0 +1 @@
+def foo(argument, *); bar(argument, *); end
diff --git a/test/prism/fixtures/whitequark/forwarded_kwrestarg.txt b/test/prism/fixtures/whitequark/forwarded_kwrestarg.txt
new file mode 100644
index 0000000000..16cd8b2913
--- /dev/null
+++ b/test/prism/fixtures/whitequark/forwarded_kwrestarg.txt
@@ -0,0 +1 @@
+def foo(**); bar(**); end
diff --git a/test/prism/fixtures/whitequark/forwarded_kwrestarg_with_additional_kwarg.txt b/test/prism/fixtures/whitequark/forwarded_kwrestarg_with_additional_kwarg.txt
new file mode 100644
index 0000000000..52759b838f
--- /dev/null
+++ b/test/prism/fixtures/whitequark/forwarded_kwrestarg_with_additional_kwarg.txt
@@ -0,0 +1 @@
+def foo(**); bar(**, from_foo: true); end
diff --git a/test/prism/fixtures/whitequark/forwarded_restarg.txt b/test/prism/fixtures/whitequark/forwarded_restarg.txt
new file mode 100644
index 0000000000..65ac2cc1ed
--- /dev/null
+++ b/test/prism/fixtures/whitequark/forwarded_restarg.txt
@@ -0,0 +1 @@
+def foo(*); bar(*); end
diff --git a/test/prism/fixtures/whitequark/gvar.txt b/test/prism/fixtures/whitequark/gvar.txt
new file mode 100644
index 0000000000..bbf13489ad
--- /dev/null
+++ b/test/prism/fixtures/whitequark/gvar.txt
@@ -0,0 +1 @@
+$foo
diff --git a/test/prism/fixtures/whitequark/gvasgn.txt b/test/prism/fixtures/whitequark/gvasgn.txt
new file mode 100644
index 0000000000..2bcc22cdd1
--- /dev/null
+++ b/test/prism/fixtures/whitequark/gvasgn.txt
@@ -0,0 +1 @@
+$var = 10
diff --git a/test/prism/fixtures/whitequark/hash_empty.txt b/test/prism/fixtures/whitequark/hash_empty.txt
new file mode 100644
index 0000000000..ffcd4415b0
--- /dev/null
+++ b/test/prism/fixtures/whitequark/hash_empty.txt
@@ -0,0 +1 @@
+{ }
diff --git a/test/prism/fixtures/whitequark/hash_hashrocket.txt b/test/prism/fixtures/whitequark/hash_hashrocket.txt
new file mode 100644
index 0000000000..2cbb3bd96d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/hash_hashrocket.txt
@@ -0,0 +1,3 @@
+{ 1 => 2 }
+
+{ 1 => 2, :foo => "bar" }
diff --git a/test/prism/fixtures/whitequark/hash_kwsplat.txt b/test/prism/fixtures/whitequark/hash_kwsplat.txt
new file mode 100644
index 0000000000..921aa97c7c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/hash_kwsplat.txt
@@ -0,0 +1 @@
+{ foo: 2, **bar }
diff --git a/test/prism/fixtures/whitequark/hash_label.txt b/test/prism/fixtures/whitequark/hash_label.txt
new file mode 100644
index 0000000000..3aacae4b69
--- /dev/null
+++ b/test/prism/fixtures/whitequark/hash_label.txt
@@ -0,0 +1 @@
+{ foo: 2 }
diff --git a/test/prism/fixtures/whitequark/hash_label_end.txt b/test/prism/fixtures/whitequark/hash_label_end.txt
new file mode 100644
index 0000000000..ac9f7c4b41
--- /dev/null
+++ b/test/prism/fixtures/whitequark/hash_label_end.txt
@@ -0,0 +1,5 @@
+f(a ? "a":1)
+
+{ 'foo': 2 }
+
+{ 'foo': 2, 'bar': {}}
diff --git a/test/prism/fixtures/whitequark/hash_pair_value_omission.txt b/test/prism/fixtures/whitequark/hash_pair_value_omission.txt
new file mode 100644
index 0000000000..9d8ccb5877
--- /dev/null
+++ b/test/prism/fixtures/whitequark/hash_pair_value_omission.txt
@@ -0,0 +1,5 @@
+{BAR:}
+
+{a:, b:}
+
+{puts:}
diff --git a/test/prism/fixtures/whitequark/heredoc.txt b/test/prism/fixtures/whitequark/heredoc.txt
new file mode 100644
index 0000000000..1bfc963f94
--- /dev/null
+++ b/test/prism/fixtures/whitequark/heredoc.txt
@@ -0,0 +1,14 @@
+<<'HERE'
+foo
+bar
+HERE
+
+<<HERE
+foo
+bar
+HERE
+
+<<`HERE`
+foo
+bar
+HERE
diff --git a/test/prism/fixtures/whitequark/if.txt b/test/prism/fixtures/whitequark/if.txt
new file mode 100644
index 0000000000..3de3525286
--- /dev/null
+++ b/test/prism/fixtures/whitequark/if.txt
@@ -0,0 +1,3 @@
+if foo then bar; end
+
+if foo; bar; end
diff --git a/test/prism/fixtures/whitequark/if_else.txt b/test/prism/fixtures/whitequark/if_else.txt
new file mode 100644
index 0000000000..62bab8138c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/if_else.txt
@@ -0,0 +1,3 @@
+if foo then bar; else baz; end
+
+if foo; bar; else baz; end
diff --git a/test/prism/fixtures/whitequark/if_elsif.txt b/test/prism/fixtures/whitequark/if_elsif.txt
new file mode 100644
index 0000000000..4d71e82214
--- /dev/null
+++ b/test/prism/fixtures/whitequark/if_elsif.txt
@@ -0,0 +1 @@
+if foo; bar; elsif baz; 1; else 2; end
diff --git a/test/prism/fixtures/whitequark/if_masgn__24.txt b/test/prism/fixtures/whitequark/if_masgn__24.txt
new file mode 100644
index 0000000000..0c2c8bb04f
--- /dev/null
+++ b/test/prism/fixtures/whitequark/if_masgn__24.txt
@@ -0,0 +1 @@
+if (a, b = foo); end
diff --git a/test/prism/fixtures/whitequark/if_mod.txt b/test/prism/fixtures/whitequark/if_mod.txt
new file mode 100644
index 0000000000..da177b5606
--- /dev/null
+++ b/test/prism/fixtures/whitequark/if_mod.txt
@@ -0,0 +1 @@
+bar if foo
diff --git a/test/prism/fixtures/whitequark/if_nl_then.txt b/test/prism/fixtures/whitequark/if_nl_then.txt
new file mode 100644
index 0000000000..b68107bad2
--- /dev/null
+++ b/test/prism/fixtures/whitequark/if_nl_then.txt
@@ -0,0 +1,2 @@
+if foo
+then bar end
diff --git a/test/prism/fixtures/whitequark/int.txt b/test/prism/fixtures/whitequark/int.txt
new file mode 100644
index 0000000000..6d419918c6
--- /dev/null
+++ b/test/prism/fixtures/whitequark/int.txt
@@ -0,0 +1,5 @@
++42
+
+-42
+
+42
diff --git a/test/prism/fixtures/whitequark/int___LINE__.txt b/test/prism/fixtures/whitequark/int___LINE__.txt
new file mode 100644
index 0000000000..05dcf7afe0
--- /dev/null
+++ b/test/prism/fixtures/whitequark/int___LINE__.txt
@@ -0,0 +1 @@
+__LINE__
diff --git a/test/prism/fixtures/whitequark/interp_digit_var.txt b/test/prism/fixtures/whitequark/interp_digit_var.txt
new file mode 100644
index 0000000000..1ae5a2e3e0
--- /dev/null
+++ b/test/prism/fixtures/whitequark/interp_digit_var.txt
@@ -0,0 +1,87 @@
+ "#@1"
+
+ "#@@1"
+
+ %I[#@1]
+
+ %I[#@@1]
+
+ %Q{#@1}
+
+ %Q{#@@1}
+
+ %W[#@1]
+
+ %W[#@@1]
+
+ %i[ #@1 ]
+
+ %i[ #@@1 ]
+
+ %q{#@1}
+
+ %q{#@@1}
+
+ %r{#@1}
+
+ %r{#@@1}
+
+ %s{#@1}
+
+ %s{#@@1}
+
+ %w[ #@1 ]
+
+ %w[ #@@1 ]
+
+ %x{#@1}
+
+ %x{#@@1}
+
+ %{#@1}
+
+ %{#@@1}
+
+ '#@1'
+
+ '#@@1'
+
+ /#@1/
+
+ /#@@1/
+
+ :"#@1"
+
+ :"#@@1"
+
+ :'#@1'
+
+ :'#@@1'
+
+ `#@1`
+
+ `#@@1`
+
+<<-"HERE"
+#@1
+HERE
+
+<<-"HERE"
+#@@1
+HERE
+
+<<-'HERE'
+#@1
+HERE
+
+<<-'HERE'
+#@@1
+HERE
+
+<<-`HERE`
+#@1
+HERE
+
+<<-`HERE`
+#@@1
+HERE
diff --git a/test/prism/fixtures/whitequark/ivar.txt b/test/prism/fixtures/whitequark/ivar.txt
new file mode 100644
index 0000000000..9149fc67f9
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ivar.txt
@@ -0,0 +1 @@
+@foo
diff --git a/test/prism/fixtures/whitequark/ivasgn.txt b/test/prism/fixtures/whitequark/ivasgn.txt
new file mode 100644
index 0000000000..ac291799db
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ivasgn.txt
@@ -0,0 +1 @@
+@var = 10
diff --git a/test/prism/fixtures/whitequark/keyword_argument_omission.txt b/test/prism/fixtures/whitequark/keyword_argument_omission.txt
new file mode 100644
index 0000000000..47883dc9a5
--- /dev/null
+++ b/test/prism/fixtures/whitequark/keyword_argument_omission.txt
@@ -0,0 +1 @@
+foo(a:, b:)
diff --git a/test/prism/fixtures/whitequark/kwarg.txt b/test/prism/fixtures/whitequark/kwarg.txt
new file mode 100644
index 0000000000..ca02a1fd2a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/kwarg.txt
@@ -0,0 +1 @@
+def f(foo:); end
diff --git a/test/prism/fixtures/whitequark/kwarg_combinations.txt b/test/prism/fixtures/whitequark/kwarg_combinations.txt
new file mode 100644
index 0000000000..1bd792856e
--- /dev/null
+++ b/test/prism/fixtures/whitequark/kwarg_combinations.txt
@@ -0,0 +1,7 @@
+def f (foo: 1, &b); end
+
+def f (foo: 1, bar: 2, **baz, &b); end
+
+def f **baz, &b; end
+
+def f *, **; end
diff --git a/test/prism/fixtures/whitequark/kwarg_no_paren.txt b/test/prism/fixtures/whitequark/kwarg_no_paren.txt
new file mode 100644
index 0000000000..cf29c273d0
--- /dev/null
+++ b/test/prism/fixtures/whitequark/kwarg_no_paren.txt
@@ -0,0 +1,5 @@
+def f foo:
+; end
+
+def f foo: -1
+; end
diff --git a/test/prism/fixtures/whitequark/kwbegin_compstmt.txt b/test/prism/fixtures/whitequark/kwbegin_compstmt.txt
new file mode 100644
index 0000000000..33ceff2489
--- /dev/null
+++ b/test/prism/fixtures/whitequark/kwbegin_compstmt.txt
@@ -0,0 +1 @@
+begin foo!; bar! end
diff --git a/test/prism/fixtures/whitequark/kwnilarg.txt b/test/prism/fixtures/whitequark/kwnilarg.txt
new file mode 100644
index 0000000000..8fc482d5af
--- /dev/null
+++ b/test/prism/fixtures/whitequark/kwnilarg.txt
@@ -0,0 +1,5 @@
+->(**nil) {}
+
+def f(**nil); end
+
+m { |**nil| }
diff --git a/test/prism/fixtures/whitequark/kwoptarg.txt b/test/prism/fixtures/whitequark/kwoptarg.txt
new file mode 100644
index 0000000000..dc3ce728d6
--- /dev/null
+++ b/test/prism/fixtures/whitequark/kwoptarg.txt
@@ -0,0 +1 @@
+def f(foo: 1); end
diff --git a/test/prism/fixtures/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt b/test/prism/fixtures/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt
new file mode 100644
index 0000000000..99dcc7239b
--- /dev/null
+++ b/test/prism/fixtures/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt
@@ -0,0 +1 @@
+def f(a: nil, **); b(**) end
diff --git a/test/prism/fixtures/whitequark/kwrestarg_named.txt b/test/prism/fixtures/whitequark/kwrestarg_named.txt
new file mode 100644
index 0000000000..e17a661001
--- /dev/null
+++ b/test/prism/fixtures/whitequark/kwrestarg_named.txt
@@ -0,0 +1 @@
+def f(**foo); end
diff --git a/test/prism/fixtures/whitequark/kwrestarg_unnamed.txt b/test/prism/fixtures/whitequark/kwrestarg_unnamed.txt
new file mode 100644
index 0000000000..1b26b1d2ac
--- /dev/null
+++ b/test/prism/fixtures/whitequark/kwrestarg_unnamed.txt
@@ -0,0 +1 @@
+def f(**); end
diff --git a/test/prism/fixtures/whitequark/lbrace_arg_after_command_args.txt b/test/prism/fixtures/whitequark/lbrace_arg_after_command_args.txt
new file mode 100644
index 0000000000..277c200c9f
--- /dev/null
+++ b/test/prism/fixtures/whitequark/lbrace_arg_after_command_args.txt
@@ -0,0 +1 @@
+let (:a) { m do; end }
diff --git a/test/prism/fixtures/whitequark/lparenarg_after_lvar__since_25.txt b/test/prism/fixtures/whitequark/lparenarg_after_lvar__since_25.txt
new file mode 100644
index 0000000000..dc3a98b1c8
--- /dev/null
+++ b/test/prism/fixtures/whitequark/lparenarg_after_lvar__since_25.txt
@@ -0,0 +1,3 @@
+foo (-1.3).abs
+
+meth (-1.3).abs
diff --git a/test/prism/fixtures/whitequark/lvar.txt b/test/prism/fixtures/whitequark/lvar.txt
new file mode 100644
index 0000000000..257cc5642c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/lvar.txt
@@ -0,0 +1 @@
+foo
diff --git a/test/prism/fixtures/whitequark/lvar_injecting_match.txt b/test/prism/fixtures/whitequark/lvar_injecting_match.txt
new file mode 100644
index 0000000000..2d18c84b57
--- /dev/null
+++ b/test/prism/fixtures/whitequark/lvar_injecting_match.txt
@@ -0,0 +1,3 @@
+/(?<a>a)/ =~ 'a'; /#{}(?<b>b)/ =~ 'b'; a; b
+
+/(?<match>bar)/ =~ 'bar'; match
diff --git a/test/prism/fixtures/whitequark/lvasgn.txt b/test/prism/fixtures/whitequark/lvasgn.txt
new file mode 100644
index 0000000000..330b8eff27
--- /dev/null
+++ b/test/prism/fixtures/whitequark/lvasgn.txt
@@ -0,0 +1 @@
+var = 10; var
diff --git a/test/prism/fixtures/whitequark/marg_combinations.txt b/test/prism/fixtures/whitequark/marg_combinations.txt
new file mode 100644
index 0000000000..aff34dcb62
--- /dev/null
+++ b/test/prism/fixtures/whitequark/marg_combinations.txt
@@ -0,0 +1,19 @@
+def f (((a))); end
+
+def f ((*)); end
+
+def f ((*, p)); end
+
+def f ((*r)); end
+
+def f ((*r, p)); end
+
+def f ((a, *)); end
+
+def f ((a, *, p)); end
+
+def f ((a, *r)); end
+
+def f ((a, *r, p)); end
+
+def f ((a, a1)); end
diff --git a/test/prism/fixtures/whitequark/masgn.txt b/test/prism/fixtures/whitequark/masgn.txt
new file mode 100644
index 0000000000..032124287c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/masgn.txt
@@ -0,0 +1,5 @@
+(foo, bar) = 1, 2
+
+foo, bar = 1, 2
+
+foo, bar, baz = 1, 2
diff --git a/test/prism/fixtures/whitequark/masgn_attr.txt b/test/prism/fixtures/whitequark/masgn_attr.txt
new file mode 100644
index 0000000000..91a703ef44
--- /dev/null
+++ b/test/prism/fixtures/whitequark/masgn_attr.txt
@@ -0,0 +1,5 @@
+self.A, foo = foo
+
+self.a, self[1, 2] = foo
+
+self::a, foo = foo
diff --git a/test/prism/fixtures/whitequark/masgn_cmd.txt b/test/prism/fixtures/whitequark/masgn_cmd.txt
new file mode 100644
index 0000000000..18e096f1ee
--- /dev/null
+++ b/test/prism/fixtures/whitequark/masgn_cmd.txt
@@ -0,0 +1 @@
+foo, bar = m foo
diff --git a/test/prism/fixtures/whitequark/masgn_const.txt b/test/prism/fixtures/whitequark/masgn_const.txt
new file mode 100644
index 0000000000..3b6fba588a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/masgn_const.txt
@@ -0,0 +1,3 @@
+::A, foo = foo
+
+self::A, foo = foo
diff --git a/test/prism/fixtures/whitequark/masgn_nested.txt b/test/prism/fixtures/whitequark/masgn_nested.txt
new file mode 100644
index 0000000000..a1ccf4e385
--- /dev/null
+++ b/test/prism/fixtures/whitequark/masgn_nested.txt
@@ -0,0 +1,3 @@
+((b, )) = foo
+
+a, (b, c) = foo
diff --git a/test/prism/fixtures/whitequark/masgn_splat.txt b/test/prism/fixtures/whitequark/masgn_splat.txt
new file mode 100644
index 0000000000..a15dab10f2
--- /dev/null
+++ b/test/prism/fixtures/whitequark/masgn_splat.txt
@@ -0,0 +1,19 @@
+* = bar
+
+*, c, d = bar
+
+*b = bar
+
+*b, c = bar
+
+@foo, @@bar = *foo
+
+a, * = bar
+
+a, *, c = bar
+
+a, *b = bar
+
+a, *b, c = bar
+
+a, b = *foo, bar
diff --git a/test/prism/fixtures/whitequark/method_definition_in_while_cond.txt b/test/prism/fixtures/whitequark/method_definition_in_while_cond.txt
new file mode 100644
index 0000000000..6ec38906a1
--- /dev/null
+++ b/test/prism/fixtures/whitequark/method_definition_in_while_cond.txt
@@ -0,0 +1,7 @@
+while def foo a = tap do end; end; break; end
+
+while def foo; tap do end; end; break; end
+
+while def self.foo a = tap do end; end; break; end
+
+while def self.foo; tap do end; end; break; end
diff --git a/test/prism/fixtures/whitequark/module.txt b/test/prism/fixtures/whitequark/module.txt
new file mode 100644
index 0000000000..f999df3791
--- /dev/null
+++ b/test/prism/fixtures/whitequark/module.txt
@@ -0,0 +1 @@
+module Foo; end
diff --git a/test/prism/fixtures/whitequark/multiple_args_with_trailing_comma.txt b/test/prism/fixtures/whitequark/multiple_args_with_trailing_comma.txt
new file mode 100644
index 0000000000..b690738757
--- /dev/null
+++ b/test/prism/fixtures/whitequark/multiple_args_with_trailing_comma.txt
@@ -0,0 +1 @@
+f{ |a, b,| }
diff --git a/test/prism/fixtures/whitequark/multiple_pattern_matches.txt b/test/prism/fixtures/whitequark/multiple_pattern_matches.txt
new file mode 100644
index 0000000000..54a4bb4774
--- /dev/null
+++ b/test/prism/fixtures/whitequark/multiple_pattern_matches.txt
@@ -0,0 +1,5 @@
+{a: 0} => a:
+{a: 0} => a:
+
+{a: 0} in a:
+{a: 0} in a:
diff --git a/test/prism/fixtures/whitequark/newline_in_hash_argument.txt b/test/prism/fixtures/whitequark/newline_in_hash_argument.txt
new file mode 100644
index 0000000000..1681844331
--- /dev/null
+++ b/test/prism/fixtures/whitequark/newline_in_hash_argument.txt
@@ -0,0 +1,14 @@
+case foo
+in a:
+0
+true
+in "b":
+0
+true
+end
+
+obj.set "foo":
+1
+
+obj.set foo:
+1
diff --git a/test/prism/fixtures/whitequark/nil.txt b/test/prism/fixtures/whitequark/nil.txt
new file mode 100644
index 0000000000..607602cfc6
--- /dev/null
+++ b/test/prism/fixtures/whitequark/nil.txt
@@ -0,0 +1 @@
+nil
diff --git a/test/prism/fixtures/whitequark/nil_expression.txt b/test/prism/fixtures/whitequark/nil_expression.txt
new file mode 100644
index 0000000000..aabf53f005
--- /dev/null
+++ b/test/prism/fixtures/whitequark/nil_expression.txt
@@ -0,0 +1,3 @@
+()
+
+begin end
diff --git a/test/prism/fixtures/whitequark/non_lvar_injecting_match.txt b/test/prism/fixtures/whitequark/non_lvar_injecting_match.txt
new file mode 100644
index 0000000000..f1eb7d3c2c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/non_lvar_injecting_match.txt
@@ -0,0 +1 @@
+/#{1}(?<match>bar)/ =~ 'bar'
diff --git a/test/prism/fixtures/whitequark/not.txt b/test/prism/fixtures/whitequark/not.txt
new file mode 100644
index 0000000000..d87f68f48c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/not.txt
@@ -0,0 +1,5 @@
+not foo
+
+not()
+
+not(foo)
diff --git a/test/prism/fixtures/whitequark/not_cmd.txt b/test/prism/fixtures/whitequark/not_cmd.txt
new file mode 100644
index 0000000000..685ec209ee
--- /dev/null
+++ b/test/prism/fixtures/whitequark/not_cmd.txt
@@ -0,0 +1 @@
+not m foo
diff --git a/test/prism/fixtures/whitequark/not_masgn__24.txt b/test/prism/fixtures/whitequark/not_masgn__24.txt
new file mode 100644
index 0000000000..cb93b9103d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/not_masgn__24.txt
@@ -0,0 +1 @@
+!(a, b = foo)
diff --git a/test/prism/fixtures/whitequark/nth_ref.txt b/test/prism/fixtures/whitequark/nth_ref.txt
new file mode 100644
index 0000000000..16ef65b105
--- /dev/null
+++ b/test/prism/fixtures/whitequark/nth_ref.txt
@@ -0,0 +1 @@
+$10
diff --git a/test/prism/fixtures/whitequark/numbered_args_after_27.txt b/test/prism/fixtures/whitequark/numbered_args_after_27.txt
new file mode 100644
index 0000000000..96fe7a32e2
--- /dev/null
+++ b/test/prism/fixtures/whitequark/numbered_args_after_27.txt
@@ -0,0 +1,7 @@
+-> do _1 + _9 end
+
+-> { _1 + _9}
+
+m do _1 + _9 end
+
+m { _1 + _9 }
diff --git a/test/prism/fixtures/whitequark/numparam_outside_block.txt b/test/prism/fixtures/whitequark/numparam_outside_block.txt
new file mode 100644
index 0000000000..37cbce182d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/numparam_outside_block.txt
@@ -0,0 +1,9 @@
+_1
+
+class << foo; _1; end
+
+class A; _1; end
+
+def self.m; _1; end
+
+module A; _1; end
diff --git a/test/prism/fixtures/whitequark/numparam_ruby_bug_19025.txt b/test/prism/fixtures/whitequark/numparam_ruby_bug_19025.txt
new file mode 100644
index 0000000000..f9ffd4329a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/numparam_ruby_bug_19025.txt
@@ -0,0 +1 @@
+p { [_1 **2] }
diff --git a/test/prism/fixtures/whitequark/op_asgn.txt b/test/prism/fixtures/whitequark/op_asgn.txt
new file mode 100644
index 0000000000..a5a28b1010
--- /dev/null
+++ b/test/prism/fixtures/whitequark/op_asgn.txt
@@ -0,0 +1,5 @@
+foo.A += 1
+
+foo.a += 1
+
+foo::a += 1
diff --git a/test/prism/fixtures/whitequark/op_asgn_cmd.txt b/test/prism/fixtures/whitequark/op_asgn_cmd.txt
new file mode 100644
index 0000000000..017aa9bef7
--- /dev/null
+++ b/test/prism/fixtures/whitequark/op_asgn_cmd.txt
@@ -0,0 +1,7 @@
+foo.A += m foo
+
+foo.a += m foo
+
+foo::A += m foo
+
+foo::a += m foo
diff --git a/test/prism/fixtures/whitequark/op_asgn_index.txt b/test/prism/fixtures/whitequark/op_asgn_index.txt
new file mode 100644
index 0000000000..92cfb225fc
--- /dev/null
+++ b/test/prism/fixtures/whitequark/op_asgn_index.txt
@@ -0,0 +1 @@
+foo[0, 1] += 2
diff --git a/test/prism/fixtures/whitequark/op_asgn_index_cmd.txt b/test/prism/fixtures/whitequark/op_asgn_index_cmd.txt
new file mode 100644
index 0000000000..161b244bd4
--- /dev/null
+++ b/test/prism/fixtures/whitequark/op_asgn_index_cmd.txt
@@ -0,0 +1 @@
+foo[0, 1] += m foo
diff --git a/test/prism/fixtures/whitequark/optarg.txt b/test/prism/fixtures/whitequark/optarg.txt
new file mode 100644
index 0000000000..9d60609961
--- /dev/null
+++ b/test/prism/fixtures/whitequark/optarg.txt
@@ -0,0 +1,3 @@
+def f foo = 1; end
+
+def f(foo=1, bar=2); end
diff --git a/test/prism/fixtures/whitequark/or.txt b/test/prism/fixtures/whitequark/or.txt
new file mode 100644
index 0000000000..c2042ebb41
--- /dev/null
+++ b/test/prism/fixtures/whitequark/or.txt
@@ -0,0 +1,3 @@
+foo or bar
+
+foo || bar
diff --git a/test/prism/fixtures/whitequark/or_asgn.txt b/test/prism/fixtures/whitequark/or_asgn.txt
new file mode 100644
index 0000000000..6e4ecc9f93
--- /dev/null
+++ b/test/prism/fixtures/whitequark/or_asgn.txt
@@ -0,0 +1,3 @@
+foo.a ||= 1
+
+foo[0, 1] ||= 2
diff --git a/test/prism/fixtures/whitequark/parser_bug_272.txt b/test/prism/fixtures/whitequark/parser_bug_272.txt
new file mode 100644
index 0000000000..2f2f2b84d2
--- /dev/null
+++ b/test/prism/fixtures/whitequark/parser_bug_272.txt
@@ -0,0 +1 @@
+a @b do |c|;end
diff --git a/test/prism/fixtures/whitequark/parser_bug_490.txt b/test/prism/fixtures/whitequark/parser_bug_490.txt
new file mode 100644
index 0000000000..cf544b1ff6
--- /dev/null
+++ b/test/prism/fixtures/whitequark/parser_bug_490.txt
@@ -0,0 +1,5 @@
+def m; class << self; A = nil; end; end
+
+def m; class << self; class C; end; end; end
+
+def m; class << self; module M; end; end; end
diff --git a/test/prism/fixtures/whitequark/parser_bug_507.txt b/test/prism/fixtures/whitequark/parser_bug_507.txt
new file mode 100644
index 0000000000..bf616b85c8
--- /dev/null
+++ b/test/prism/fixtures/whitequark/parser_bug_507.txt
@@ -0,0 +1 @@
+m = -> *args do end
diff --git a/test/prism/fixtures/whitequark/parser_bug_518.txt b/test/prism/fixtures/whitequark/parser_bug_518.txt
new file mode 100644
index 0000000000..22f4afe3c8
--- /dev/null
+++ b/test/prism/fixtures/whitequark/parser_bug_518.txt
@@ -0,0 +1,2 @@
+class A < B
+end
diff --git a/test/prism/fixtures/whitequark/parser_bug_525.txt b/test/prism/fixtures/whitequark/parser_bug_525.txt
new file mode 100644
index 0000000000..59d0e735b4
--- /dev/null
+++ b/test/prism/fixtures/whitequark/parser_bug_525.txt
@@ -0,0 +1 @@
+m1 :k => m2 do; m3() do end; end
diff --git a/test/prism/fixtures/whitequark/parser_bug_604.txt b/test/prism/fixtures/whitequark/parser_bug_604.txt
new file mode 100644
index 0000000000..7eb91c2f46
--- /dev/null
+++ b/test/prism/fixtures/whitequark/parser_bug_604.txt
@@ -0,0 +1 @@
+m a + b do end
diff --git a/test/prism/fixtures/whitequark/parser_bug_640.txt b/test/prism/fixtures/whitequark/parser_bug_640.txt
new file mode 100644
index 0000000000..fb62ded04c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/parser_bug_640.txt
@@ -0,0 +1,4 @@
+<<~FOO
+ baz\
+ qux
+FOO
diff --git a/test/prism/fixtures/whitequark/parser_bug_645.txt b/test/prism/fixtures/whitequark/parser_bug_645.txt
new file mode 100644
index 0000000000..cb1e5a0dcf
--- /dev/null
+++ b/test/prism/fixtures/whitequark/parser_bug_645.txt
@@ -0,0 +1 @@
+-> (arg={}) {}
diff --git a/test/prism/fixtures/whitequark/parser_bug_830.txt b/test/prism/fixtures/whitequark/parser_bug_830.txt
new file mode 100644
index 0000000000..e5865e960d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/parser_bug_830.txt
@@ -0,0 +1 @@
+/\(/
diff --git a/test/prism/fixtures/whitequark/parser_bug_989.txt b/test/prism/fixtures/whitequark/parser_bug_989.txt
new file mode 100644
index 0000000000..b7b99612b4
--- /dev/null
+++ b/test/prism/fixtures/whitequark/parser_bug_989.txt
@@ -0,0 +1,3 @@
+ <<-HERE
+ content
+ HERE
diff --git a/test/prism/fixtures/whitequark/parser_drops_truncated_parts_of_squiggly_heredoc.txt b/test/prism/fixtures/whitequark/parser_drops_truncated_parts_of_squiggly_heredoc.txt
new file mode 100644
index 0000000000..bddae8e153
--- /dev/null
+++ b/test/prism/fixtures/whitequark/parser_drops_truncated_parts_of_squiggly_heredoc.txt
@@ -0,0 +1,3 @@
+<<~HERE
+ #{}
+HERE
diff --git a/test/prism/fixtures/whitequark/parser_slash_slash_n_escaping_in_literals.txt b/test/prism/fixtures/whitequark/parser_slash_slash_n_escaping_in_literals.txt
new file mode 100644
index 0000000000..564cebdd74
--- /dev/null
+++ b/test/prism/fixtures/whitequark/parser_slash_slash_n_escaping_in_literals.txt
@@ -0,0 +1,62 @@
+"a\
+b"
+
+%I{a\
+b}
+
+%Q{a\
+b}
+
+%W{a\
+b}
+
+%i{a\
+b}
+
+%q{a\
+b}
+
+%r{a\
+b}
+
+%s{a\
+b}
+
+%w{a\
+b}
+
+%x{a\
+b}
+
+%{a\
+b}
+
+'a\
+b'
+
+/a\
+b/
+
+:"a\
+b"
+
+:'a\
+b'
+
+<<-"HERE"
+a\
+b
+HERE
+
+<<-'HERE'
+a\
+b
+HERE
+
+<<-`HERE`
+a\
+b
+HERE
+
+`a\
+b`
diff --git a/test/prism/fixtures/whitequark/pattern_matching__FILE__LINE_literals.txt b/test/prism/fixtures/whitequark/pattern_matching__FILE__LINE_literals.txt
new file mode 100644
index 0000000000..fe0edaed55
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching__FILE__LINE_literals.txt
@@ -0,0 +1,4 @@
+ case [__FILE__, __LINE__ + 1, __ENCODING__]
+ in [__FILE__, __LINE__, __ENCODING__]
+ end
+
diff --git a/test/prism/fixtures/whitequark/pattern_matching_blank_else.txt b/test/prism/fixtures/whitequark/pattern_matching_blank_else.txt
new file mode 100644
index 0000000000..6bf059af41
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_blank_else.txt
@@ -0,0 +1 @@
+case 1; in 2; 3; else; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_const_pattern.txt b/test/prism/fixtures/whitequark/pattern_matching_const_pattern.txt
new file mode 100644
index 0000000000..82821dbc83
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_const_pattern.txt
@@ -0,0 +1,11 @@
+case foo; in A() then true; end
+
+case foo; in A(1, 2) then true; end
+
+case foo; in A(x:) then true; end
+
+case foo; in A[1, 2] then true; end
+
+case foo; in A[] then true; end
+
+case foo; in A[x:] then true; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_constants.txt b/test/prism/fixtures/whitequark/pattern_matching_constants.txt
new file mode 100644
index 0000000000..aba764ff35
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_constants.txt
@@ -0,0 +1,5 @@
+case foo; in ::A then true; end
+
+case foo; in A then true; end
+
+case foo; in A::B then true; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_else.txt b/test/prism/fixtures/whitequark/pattern_matching_else.txt
new file mode 100644
index 0000000000..29f14c91ab
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_else.txt
@@ -0,0 +1 @@
+case 1; in 2; 3; else; 4; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_explicit_array_match.txt b/test/prism/fixtures/whitequark/pattern_matching_explicit_array_match.txt
new file mode 100644
index 0000000000..61e518d0fb
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_explicit_array_match.txt
@@ -0,0 +1,19 @@
+case foo; in [*, x] then true; end
+
+case foo; in [*x, y] then true; end
+
+case foo; in [x, *, y] then true; end
+
+case foo; in [x, *y, z] then true; end
+
+case foo; in [x, y, *] then true; end
+
+case foo; in [x, y, *z] then true; end
+
+case foo; in [x, y,] then true; end
+
+case foo; in [x, y] then true; end
+
+case foo; in [x,] then nil; end
+
+case foo; in [x] then nil; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_expr_in_paren.txt b/test/prism/fixtures/whitequark/pattern_matching_expr_in_paren.txt
new file mode 100644
index 0000000000..9b2e91b70d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_expr_in_paren.txt
@@ -0,0 +1 @@
+case foo; in (1) then true; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_hash.txt b/test/prism/fixtures/whitequark/pattern_matching_hash.txt
new file mode 100644
index 0000000000..b26f2c59dc
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_hash.txt
@@ -0,0 +1,48 @@
+case foo;
+ in a: {b:}, c:
+ p c
+ ; end
+
+case foo;
+ in {Foo: 42
+ }
+ false
+ ; end
+
+case foo;
+ in {a:
+ 2}
+ false
+ ; end
+
+case foo;
+ in {a:
+ }
+ true
+ ; end
+
+case foo;
+ in {a: 1
+ }
+ false
+ ; end
+
+case foo; in ** then true; end
+
+case foo; in **a then true; end
+
+case foo; in a: 1 then true; end
+
+case foo; in a: 1, _a:, ** then true; end
+
+case foo; in a: 1, b: 2 then true; end
+
+case foo; in a: then true; end
+
+case foo; in a:, b: then true; end
+
+case foo; in { a: 1 } then true; end
+
+case foo; in { a: 1, } then true; end
+
+case foo; in {} then true; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_if_unless_modifiers.txt b/test/prism/fixtures/whitequark/pattern_matching_if_unless_modifiers.txt
new file mode 100644
index 0000000000..05ca317355
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_if_unless_modifiers.txt
@@ -0,0 +1,3 @@
+case foo; in x if true; nil; end
+
+case foo; in x unless true; nil; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_implicit_array_match.txt b/test/prism/fixtures/whitequark/pattern_matching_implicit_array_match.txt
new file mode 100644
index 0000000000..360c5150a5
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_implicit_array_match.txt
@@ -0,0 +1,15 @@
+case foo; in * then nil; end
+
+case foo; in *x then nil; end
+
+case foo; in *x, y, z then nil; end
+
+case foo; in 1, "a", [], {} then nil; end
+
+case foo; in x, *y, z then nil; end
+
+case foo; in x, then nil; end
+
+case foo; in x, y then nil; end
+
+case foo; in x, y, then nil; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_keyword_variable.txt b/test/prism/fixtures/whitequark/pattern_matching_keyword_variable.txt
new file mode 100644
index 0000000000..83c7a06b09
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_keyword_variable.txt
@@ -0,0 +1 @@
+case foo; in self then true; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_lambda.txt b/test/prism/fixtures/whitequark/pattern_matching_lambda.txt
new file mode 100644
index 0000000000..eeccdc70e0
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_lambda.txt
@@ -0,0 +1 @@
+case foo; in ->{ 42 } then true; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_match_alt.txt b/test/prism/fixtures/whitequark/pattern_matching_match_alt.txt
new file mode 100644
index 0000000000..6c6549916d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_match_alt.txt
@@ -0,0 +1 @@
+case foo; in 1 | 2 then true; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_match_as.txt b/test/prism/fixtures/whitequark/pattern_matching_match_as.txt
new file mode 100644
index 0000000000..2a105f9f36
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_match_as.txt
@@ -0,0 +1 @@
+case foo; in 1 => a then true; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_nil_pattern.txt b/test/prism/fixtures/whitequark/pattern_matching_nil_pattern.txt
new file mode 100644
index 0000000000..46dce94a2d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_nil_pattern.txt
@@ -0,0 +1 @@
+case foo; in **nil then true; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_no_body.txt b/test/prism/fixtures/whitequark/pattern_matching_no_body.txt
new file mode 100644
index 0000000000..73b471d352
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_no_body.txt
@@ -0,0 +1 @@
+case foo; in 1; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_ranges.txt b/test/prism/fixtures/whitequark/pattern_matching_ranges.txt
new file mode 100644
index 0000000000..7e603e77b0
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_ranges.txt
@@ -0,0 +1,11 @@
+case foo; in ...2 then true; end
+
+case foo; in ..2 then true; end
+
+case foo; in 1.. then true; end
+
+case foo; in 1... then true; end
+
+case foo; in 1...2 then true; end
+
+case foo; in 1..2 then true; end
diff --git a/test/prism/fixtures/whitequark/pattern_matching_single_line.txt b/test/prism/fixtures/whitequark/pattern_matching_single_line.txt
new file mode 100644
index 0000000000..12279afa24
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_single_line.txt
@@ -0,0 +1,3 @@
+1 => [a]; a
+
+1 in [a]; a
diff --git a/test/prism/fixtures/whitequark/pattern_matching_single_line_allowed_omission_of_parentheses.txt b/test/prism/fixtures/whitequark/pattern_matching_single_line_allowed_omission_of_parentheses.txt
new file mode 100644
index 0000000000..1e429335d0
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_single_line_allowed_omission_of_parentheses.txt
@@ -0,0 +1,11 @@
+[1, 2] => a, b; a
+
+[1, 2] in a, b; a
+
+{a: 1} => a:; a
+
+{a: 1} in a:; a
+
+{key: :value} => key: value; value
+
+{key: :value} in key: value; value
diff --git a/test/prism/fixtures/whitequark/pattern_matching_single_match.txt b/test/prism/fixtures/whitequark/pattern_matching_single_match.txt
new file mode 100644
index 0000000000..c174376585
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pattern_matching_single_match.txt
@@ -0,0 +1 @@
+case foo; in x then x; end
diff --git a/test/prism/fixtures/whitequark/pin_expr.txt b/test/prism/fixtures/whitequark/pin_expr.txt
new file mode 100644
index 0000000000..a072c7c194
--- /dev/null
+++ b/test/prism/fixtures/whitequark/pin_expr.txt
@@ -0,0 +1,14 @@
+case foo; in ^$TestPatternMatching; end
+
+case foo; in ^(0+0) then nil; end
+
+case foo; in ^(1
+); end
+
+case foo; in ^(42) then nil; end
+
+case foo; in ^@@TestPatternMatching; end
+
+case foo; in ^@a; end
+
+case foo; in { foo: ^(42) } then nil; end
diff --git a/test/prism/fixtures/whitequark/postexe.txt b/test/prism/fixtures/whitequark/postexe.txt
new file mode 100644
index 0000000000..baee33af66
--- /dev/null
+++ b/test/prism/fixtures/whitequark/postexe.txt
@@ -0,0 +1 @@
+END { 1 }
diff --git a/test/prism/fixtures/whitequark/preexe.txt b/test/prism/fixtures/whitequark/preexe.txt
new file mode 100644
index 0000000000..9e802f3f4e
--- /dev/null
+++ b/test/prism/fixtures/whitequark/preexe.txt
@@ -0,0 +1 @@
+BEGIN { 1 }
diff --git a/test/prism/fixtures/whitequark/procarg0.txt b/test/prism/fixtures/whitequark/procarg0.txt
new file mode 100644
index 0000000000..74cae2c2eb
--- /dev/null
+++ b/test/prism/fixtures/whitequark/procarg0.txt
@@ -0,0 +1,3 @@
+m { |(foo, bar)| }
+
+m { |foo| }
diff --git a/test/prism/fixtures/whitequark/procarg0_legacy.txt b/test/prism/fixtures/whitequark/procarg0_legacy.txt
new file mode 100644
index 0000000000..a985f15b6e
--- /dev/null
+++ b/test/prism/fixtures/whitequark/procarg0_legacy.txt
@@ -0,0 +1 @@
+f{ |a| }
diff --git a/test/prism/fixtures/whitequark/range_exclusive.txt b/test/prism/fixtures/whitequark/range_exclusive.txt
new file mode 100644
index 0000000000..9e07faed27
--- /dev/null
+++ b/test/prism/fixtures/whitequark/range_exclusive.txt
@@ -0,0 +1 @@
+1...2
diff --git a/test/prism/fixtures/whitequark/range_inclusive.txt b/test/prism/fixtures/whitequark/range_inclusive.txt
new file mode 100644
index 0000000000..8c12abf7de
--- /dev/null
+++ b/test/prism/fixtures/whitequark/range_inclusive.txt
@@ -0,0 +1 @@
+1..2
diff --git a/test/prism/fixtures/whitequark/rational.txt b/test/prism/fixtures/whitequark/rational.txt
new file mode 100644
index 0000000000..e11cacc742
--- /dev/null
+++ b/test/prism/fixtures/whitequark/rational.txt
@@ -0,0 +1,3 @@
+42.1r
+
+42r
diff --git a/test/prism/fixtures/whitequark/regex_interp.txt b/test/prism/fixtures/whitequark/regex_interp.txt
new file mode 100644
index 0000000000..f9ad7fcbc8
--- /dev/null
+++ b/test/prism/fixtures/whitequark/regex_interp.txt
@@ -0,0 +1 @@
+/foo#{bar}baz/
diff --git a/test/prism/fixtures/whitequark/regex_plain.txt b/test/prism/fixtures/whitequark/regex_plain.txt
new file mode 100644
index 0000000000..b86faecf98
--- /dev/null
+++ b/test/prism/fixtures/whitequark/regex_plain.txt
@@ -0,0 +1 @@
+/source/im
diff --git a/test/prism/fixtures/whitequark/resbody_list.txt b/test/prism/fixtures/whitequark/resbody_list.txt
new file mode 100644
index 0000000000..e40d45fc45
--- /dev/null
+++ b/test/prism/fixtures/whitequark/resbody_list.txt
@@ -0,0 +1 @@
+begin; meth; rescue Exception; bar; end
diff --git a/test/prism/fixtures/whitequark/resbody_list_mrhs.txt b/test/prism/fixtures/whitequark/resbody_list_mrhs.txt
new file mode 100644
index 0000000000..92b8bb2c02
--- /dev/null
+++ b/test/prism/fixtures/whitequark/resbody_list_mrhs.txt
@@ -0,0 +1 @@
+begin; meth; rescue Exception, foo; bar; end
diff --git a/test/prism/fixtures/whitequark/resbody_list_var.txt b/test/prism/fixtures/whitequark/resbody_list_var.txt
new file mode 100644
index 0000000000..0a2fb90b6d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/resbody_list_var.txt
@@ -0,0 +1 @@
+begin; meth; rescue foo => ex; bar; end
diff --git a/test/prism/fixtures/whitequark/resbody_var.txt b/test/prism/fixtures/whitequark/resbody_var.txt
new file mode 100644
index 0000000000..2104ac58e7
--- /dev/null
+++ b/test/prism/fixtures/whitequark/resbody_var.txt
@@ -0,0 +1,3 @@
+begin; meth; rescue => @ex; bar; end
+
+begin; meth; rescue => ex; bar; end
diff --git a/test/prism/fixtures/whitequark/rescue.txt b/test/prism/fixtures/whitequark/rescue.txt
new file mode 100644
index 0000000000..2d3be9dc56
--- /dev/null
+++ b/test/prism/fixtures/whitequark/rescue.txt
@@ -0,0 +1 @@
+begin; meth; rescue; foo; end
diff --git a/test/prism/fixtures/whitequark/rescue_else.txt b/test/prism/fixtures/whitequark/rescue_else.txt
new file mode 100644
index 0000000000..a22f8d100e
--- /dev/null
+++ b/test/prism/fixtures/whitequark/rescue_else.txt
@@ -0,0 +1 @@
+begin; meth; rescue; foo; else; bar; end
diff --git a/test/prism/fixtures/whitequark/rescue_else_ensure.txt b/test/prism/fixtures/whitequark/rescue_else_ensure.txt
new file mode 100644
index 0000000000..167eee194a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/rescue_else_ensure.txt
@@ -0,0 +1 @@
+begin; meth; rescue; baz; else foo; ensure; bar end
diff --git a/test/prism/fixtures/whitequark/rescue_ensure.txt b/test/prism/fixtures/whitequark/rescue_ensure.txt
new file mode 100644
index 0000000000..8237257c41
--- /dev/null
+++ b/test/prism/fixtures/whitequark/rescue_ensure.txt
@@ -0,0 +1 @@
+begin; meth; rescue; baz; ensure; bar; end
diff --git a/test/prism/fixtures/whitequark/rescue_in_lambda_block.txt b/test/prism/fixtures/whitequark/rescue_in_lambda_block.txt
new file mode 100644
index 0000000000..ccd8ed72c5
--- /dev/null
+++ b/test/prism/fixtures/whitequark/rescue_in_lambda_block.txt
@@ -0,0 +1 @@
+-> do rescue; end
diff --git a/test/prism/fixtures/whitequark/rescue_mod.txt b/test/prism/fixtures/whitequark/rescue_mod.txt
new file mode 100644
index 0000000000..06375d3e9b
--- /dev/null
+++ b/test/prism/fixtures/whitequark/rescue_mod.txt
@@ -0,0 +1 @@
+meth rescue bar
diff --git a/test/prism/fixtures/whitequark/rescue_mod_asgn.txt b/test/prism/fixtures/whitequark/rescue_mod_asgn.txt
new file mode 100644
index 0000000000..abf7cd9a3d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/rescue_mod_asgn.txt
@@ -0,0 +1 @@
+foo = meth rescue bar
diff --git a/test/prism/fixtures/whitequark/rescue_mod_masgn.txt b/test/prism/fixtures/whitequark/rescue_mod_masgn.txt
new file mode 100644
index 0000000000..0716eb1f67
--- /dev/null
+++ b/test/prism/fixtures/whitequark/rescue_mod_masgn.txt
@@ -0,0 +1 @@
+foo, bar = meth rescue [1, 2]
diff --git a/test/prism/fixtures/whitequark/rescue_mod_op_assign.txt b/test/prism/fixtures/whitequark/rescue_mod_op_assign.txt
new file mode 100644
index 0000000000..178efa3a20
--- /dev/null
+++ b/test/prism/fixtures/whitequark/rescue_mod_op_assign.txt
@@ -0,0 +1 @@
+foo += meth rescue bar
diff --git a/test/prism/fixtures/whitequark/rescue_without_begin_end.txt b/test/prism/fixtures/whitequark/rescue_without_begin_end.txt
new file mode 100644
index 0000000000..8416569e2c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/rescue_without_begin_end.txt
@@ -0,0 +1 @@
+meth do; foo; rescue; bar; end
diff --git a/test/prism/fixtures/whitequark/restarg_named.txt b/test/prism/fixtures/whitequark/restarg_named.txt
new file mode 100644
index 0000000000..355cd8f493
--- /dev/null
+++ b/test/prism/fixtures/whitequark/restarg_named.txt
@@ -0,0 +1 @@
+def f(*foo); end
diff --git a/test/prism/fixtures/whitequark/restarg_unnamed.txt b/test/prism/fixtures/whitequark/restarg_unnamed.txt
new file mode 100644
index 0000000000..c9932dd30c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/restarg_unnamed.txt
@@ -0,0 +1 @@
+def f(*); end
diff --git a/test/prism/fixtures/whitequark/return.txt b/test/prism/fixtures/whitequark/return.txt
new file mode 100644
index 0000000000..e3d966bda0
--- /dev/null
+++ b/test/prism/fixtures/whitequark/return.txt
@@ -0,0 +1,7 @@
+return
+
+return foo
+
+return()
+
+return(foo)
diff --git a/test/prism/fixtures/whitequark/return_block.txt b/test/prism/fixtures/whitequark/return_block.txt
new file mode 100644
index 0000000000..00723a7517
--- /dev/null
+++ b/test/prism/fixtures/whitequark/return_block.txt
@@ -0,0 +1 @@
+return fun foo do end
diff --git a/test/prism/fixtures/whitequark/ruby_bug_10279.txt b/test/prism/fixtures/whitequark/ruby_bug_10279.txt
new file mode 100644
index 0000000000..4d0fb213d8
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_10279.txt
@@ -0,0 +1 @@
+{a: if true then 42 end}
diff --git a/test/prism/fixtures/whitequark/ruby_bug_10653.txt b/test/prism/fixtures/whitequark/ruby_bug_10653.txt
new file mode 100644
index 0000000000..51354a1f70
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_10653.txt
@@ -0,0 +1,5 @@
+false ? raise do end : tap do end
+
+false ? raise {} : tap {}
+
+true ? 1.tap do |n| p n end : 0
diff --git a/test/prism/fixtures/whitequark/ruby_bug_11107.txt b/test/prism/fixtures/whitequark/ruby_bug_11107.txt
new file mode 100644
index 0000000000..1f28cb06f6
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_11107.txt
@@ -0,0 +1 @@
+p ->() do a() do end end
diff --git a/test/prism/fixtures/whitequark/ruby_bug_11380.txt b/test/prism/fixtures/whitequark/ruby_bug_11380.txt
new file mode 100644
index 0000000000..1631548e3a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_11380.txt
@@ -0,0 +1 @@
+p -> { :hello }, a: 1 do end
diff --git a/test/prism/fixtures/whitequark/ruby_bug_11873.txt b/test/prism/fixtures/whitequark/ruby_bug_11873.txt
new file mode 100644
index 0000000000..a25aa9e267
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_11873.txt
@@ -0,0 +1,23 @@
+a b(c d), "x" do end
+
+a b(c d), /x/ do end
+
+a b(c d), /x/m do end
+
+a b(c(d)), "x" do end
+
+a b(c(d)), /x/ do end
+
+a b(c(d)), /x/m do end
+
+a b{c d}, "x" do end
+
+a b{c d}, /x/ do end
+
+a b{c d}, /x/m do end
+
+a b{c(d)}, "x" do end
+
+a b{c(d)}, /x/ do end
+
+a b{c(d)}, /x/m do end
diff --git a/test/prism/fixtures/whitequark/ruby_bug_11873_a.txt b/test/prism/fixtures/whitequark/ruby_bug_11873_a.txt
new file mode 100644
index 0000000000..1856235ce5
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_11873_a.txt
@@ -0,0 +1,39 @@
+a b(c d), 1 do end
+
+a b(c d), 1.0 do end
+
+a b(c d), 1.0i do end
+
+a b(c d), 1.0r do end
+
+a b(c d), :e do end
+
+a b(c(d)), 1 do end
+
+a b(c(d)), 1.0 do end
+
+a b(c(d)), 1.0i do end
+
+a b(c(d)), 1.0r do end
+
+a b(c(d)), :e do end
+
+a b{c d}, 1 do end
+
+a b{c d}, 1.0 do end
+
+a b{c d}, 1.0i do end
+
+a b{c d}, 1.0r do end
+
+a b{c d}, :e do end
+
+a b{c(d)}, 1 do end
+
+a b{c(d)}, 1.0 do end
+
+a b{c(d)}, 1.0i do end
+
+a b{c(d)}, 1.0r do end
+
+a b{c(d)}, :e do end
diff --git a/test/prism/fixtures/whitequark/ruby_bug_11873_b.txt b/test/prism/fixtures/whitequark/ruby_bug_11873_b.txt
new file mode 100644
index 0000000000..1b86662008
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_11873_b.txt
@@ -0,0 +1 @@
+p p{p(p);p p}, tap do end
diff --git a/test/prism/fixtures/whitequark/ruby_bug_11989.txt b/test/prism/fixtures/whitequark/ruby_bug_11989.txt
new file mode 100644
index 0000000000..d49b8614ed
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_11989.txt
@@ -0,0 +1,3 @@
+p <<~"E"
+ x\n y
+E
diff --git a/test/prism/fixtures/whitequark/ruby_bug_11990.txt b/test/prism/fixtures/whitequark/ruby_bug_11990.txt
new file mode 100644
index 0000000000..d0fe7b2739
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_11990.txt
@@ -0,0 +1,3 @@
+p <<~E " y"
+ x
+E
diff --git a/test/prism/fixtures/whitequark/ruby_bug_12073.txt b/test/prism/fixtures/whitequark/ruby_bug_12073.txt
new file mode 100644
index 0000000000..b2e3784422
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_12073.txt
@@ -0,0 +1,3 @@
+a = 1; a b: 1
+
+def foo raise; raise A::B, ''; end
diff --git a/test/prism/fixtures/whitequark/ruby_bug_12402.txt b/test/prism/fixtures/whitequark/ruby_bug_12402.txt
new file mode 100644
index 0000000000..060d5d95a1
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_12402.txt
@@ -0,0 +1,27 @@
+foo += raise bar rescue nil
+
+foo += raise(bar) rescue nil
+
+foo = raise bar rescue nil
+
+foo = raise(bar) rescue nil
+
+foo.C += raise bar rescue nil
+
+foo.C += raise(bar) rescue nil
+
+foo.m += raise bar rescue nil
+
+foo.m += raise(bar) rescue nil
+
+foo::C ||= raise bar rescue nil
+
+foo::C ||= raise(bar) rescue nil
+
+foo::m += raise bar rescue nil
+
+foo::m += raise(bar) rescue nil
+
+foo[0] += raise bar rescue nil
+
+foo[0] += raise(bar) rescue nil
diff --git a/test/prism/fixtures/whitequark/ruby_bug_12669.txt b/test/prism/fixtures/whitequark/ruby_bug_12669.txt
new file mode 100644
index 0000000000..cd89689446
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_12669.txt
@@ -0,0 +1,7 @@
+a += b += raise :x
+
+a += b = raise :x
+
+a = b += raise :x
+
+a = b = raise :x
diff --git a/test/prism/fixtures/whitequark/ruby_bug_12686.txt b/test/prism/fixtures/whitequark/ruby_bug_12686.txt
new file mode 100644
index 0000000000..7742e791b8
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_12686.txt
@@ -0,0 +1 @@
+f (g rescue nil)
diff --git a/test/prism/fixtures/whitequark/ruby_bug_13547.txt b/test/prism/fixtures/whitequark/ruby_bug_13547.txt
new file mode 100644
index 0000000000..29eafc3a4c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_13547.txt
@@ -0,0 +1 @@
+meth[] {}
diff --git a/test/prism/fixtures/whitequark/ruby_bug_14690.txt b/test/prism/fixtures/whitequark/ruby_bug_14690.txt
new file mode 100644
index 0000000000..b73b1d8aad
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_14690.txt
@@ -0,0 +1 @@
+let () { m(a) do; end }
diff --git a/test/prism/fixtures/whitequark/ruby_bug_15789.txt b/test/prism/fixtures/whitequark/ruby_bug_15789.txt
new file mode 100644
index 0000000000..6324db5110
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_15789.txt
@@ -0,0 +1,3 @@
+m ->(a = ->{_1}) {a}
+
+m ->(a: ->{_1}) {a}
diff --git a/test/prism/fixtures/whitequark/ruby_bug_18878.txt b/test/prism/fixtures/whitequark/ruby_bug_18878.txt
new file mode 100644
index 0000000000..583280c9e3
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_18878.txt
@@ -0,0 +1 @@
+Foo::Bar { |a| 42 }
diff --git a/test/prism/fixtures/whitequark/ruby_bug_19281.txt b/test/prism/fixtures/whitequark/ruby_bug_19281.txt
new file mode 100644
index 0000000000..cd154f9756
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_19281.txt
@@ -0,0 +1,7 @@
+a.b (1;2),(3),(4)
+
+a.b (;),(),()
+
+p (1;2),(3),(4)
+
+p (;),(),()
diff --git a/test/prism/fixtures/whitequark/ruby_bug_19539.txt b/test/prism/fixtures/whitequark/ruby_bug_19539.txt
new file mode 100644
index 0000000000..b2d052d94d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_19539.txt
@@ -0,0 +1,9 @@
+<<' FOO'
+[Bug #19539]
+ FOO
+
+
+<<-' FOO'
+[Bug #19539]
+ FOO
+
diff --git a/test/prism/fixtures/whitequark/ruby_bug_9669.txt b/test/prism/fixtures/whitequark/ruby_bug_9669.txt
new file mode 100644
index 0000000000..60dfa09d51
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ruby_bug_9669.txt
@@ -0,0 +1,8 @@
+def a b:
+return
+end
+
+o = {
+a:
+1
+}
diff --git a/test/prism/fixtures/whitequark/sclass.txt b/test/prism/fixtures/whitequark/sclass.txt
new file mode 100644
index 0000000000..e6aadaef21
--- /dev/null
+++ b/test/prism/fixtures/whitequark/sclass.txt
@@ -0,0 +1 @@
+class << foo; nil; end
diff --git a/test/prism/fixtures/whitequark/self.txt b/test/prism/fixtures/whitequark/self.txt
new file mode 100644
index 0000000000..31f9efa4a1
--- /dev/null
+++ b/test/prism/fixtures/whitequark/self.txt
@@ -0,0 +1 @@
+self
diff --git a/test/prism/fixtures/whitequark/send_attr_asgn.txt b/test/prism/fixtures/whitequark/send_attr_asgn.txt
new file mode 100644
index 0000000000..b477966b2a
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_attr_asgn.txt
@@ -0,0 +1,7 @@
+foo.A = 1
+
+foo.a = 1
+
+foo::A = 1
+
+foo::a = 1
diff --git a/test/prism/fixtures/whitequark/send_attr_asgn_conditional.txt b/test/prism/fixtures/whitequark/send_attr_asgn_conditional.txt
new file mode 100644
index 0000000000..1279e02cfc
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_attr_asgn_conditional.txt
@@ -0,0 +1 @@
+a&.b = 1
diff --git a/test/prism/fixtures/whitequark/send_binary_op.txt b/test/prism/fixtures/whitequark/send_binary_op.txt
new file mode 100644
index 0000000000..3e3e9300b3
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_binary_op.txt
@@ -0,0 +1,41 @@
+foo != 1
+
+foo !~ 1
+
+foo % 1
+
+foo & 1
+
+foo * 1
+
+foo ** 1
+
+foo + 1
+
+foo - 1
+
+foo / 1
+
+foo < 1
+
+foo << 1
+
+foo <= 1
+
+foo <=> 1
+
+foo == 1
+
+foo === 1
+
+foo =~ 1
+
+foo > 1
+
+foo >= 1
+
+foo >> 1
+
+foo ^ 1
+
+foo | 1
diff --git a/test/prism/fixtures/whitequark/send_block_chain_cmd.txt b/test/prism/fixtures/whitequark/send_block_chain_cmd.txt
new file mode 100644
index 0000000000..c6fe1aab0e
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_block_chain_cmd.txt
@@ -0,0 +1,13 @@
+meth 1 do end.fun bar
+
+meth 1 do end.fun bar do end
+
+meth 1 do end.fun {}
+
+meth 1 do end.fun(bar)
+
+meth 1 do end.fun(bar) {}
+
+meth 1 do end::fun bar
+
+meth 1 do end::fun(bar)
diff --git a/test/prism/fixtures/whitequark/send_block_conditional.txt b/test/prism/fixtures/whitequark/send_block_conditional.txt
new file mode 100644
index 0000000000..dcc8361762
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_block_conditional.txt
@@ -0,0 +1 @@
+foo&.bar {}
diff --git a/test/prism/fixtures/whitequark/send_call.txt b/test/prism/fixtures/whitequark/send_call.txt
new file mode 100644
index 0000000000..99701270bb
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_call.txt
@@ -0,0 +1,3 @@
+foo.(1)
+
+foo::(1)
diff --git a/test/prism/fixtures/whitequark/send_conditional.txt b/test/prism/fixtures/whitequark/send_conditional.txt
new file mode 100644
index 0000000000..8ecd27e0fe
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_conditional.txt
@@ -0,0 +1 @@
+a&.b
diff --git a/test/prism/fixtures/whitequark/send_index.txt b/test/prism/fixtures/whitequark/send_index.txt
new file mode 100644
index 0000000000..f9c4dafc4e
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_index.txt
@@ -0,0 +1 @@
+foo[1, 2]
diff --git a/test/prism/fixtures/whitequark/send_index_asgn.txt b/test/prism/fixtures/whitequark/send_index_asgn.txt
new file mode 100644
index 0000000000..e232fa3b96
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_index_asgn.txt
@@ -0,0 +1 @@
+foo[1, 2] = 3
diff --git a/test/prism/fixtures/whitequark/send_index_asgn_legacy.txt b/test/prism/fixtures/whitequark/send_index_asgn_legacy.txt
new file mode 100644
index 0000000000..e232fa3b96
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_index_asgn_legacy.txt
@@ -0,0 +1 @@
+foo[1, 2] = 3
diff --git a/test/prism/fixtures/whitequark/send_index_cmd.txt b/test/prism/fixtures/whitequark/send_index_cmd.txt
new file mode 100644
index 0000000000..32090e7536
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_index_cmd.txt
@@ -0,0 +1 @@
+foo[m bar]
diff --git a/test/prism/fixtures/whitequark/send_index_legacy.txt b/test/prism/fixtures/whitequark/send_index_legacy.txt
new file mode 100644
index 0000000000..f9c4dafc4e
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_index_legacy.txt
@@ -0,0 +1 @@
+foo[1, 2]
diff --git a/test/prism/fixtures/whitequark/send_lambda.txt b/test/prism/fixtures/whitequark/send_lambda.txt
new file mode 100644
index 0000000000..eadd6c9c03
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_lambda.txt
@@ -0,0 +1,5 @@
+-> * { }
+
+-> do end
+
+->{ }
diff --git a/test/prism/fixtures/whitequark/send_lambda_args.txt b/test/prism/fixtures/whitequark/send_lambda_args.txt
new file mode 100644
index 0000000000..68392f2f34
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_lambda_args.txt
@@ -0,0 +1,3 @@
+-> (a) { }
+
+->(a) { }
diff --git a/test/prism/fixtures/whitequark/send_lambda_args_noparen.txt b/test/prism/fixtures/whitequark/send_lambda_args_noparen.txt
new file mode 100644
index 0000000000..c0ae077f95
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_lambda_args_noparen.txt
@@ -0,0 +1,3 @@
+-> a: 1 { }
+
+-> a: { }
diff --git a/test/prism/fixtures/whitequark/send_lambda_args_shadow.txt b/test/prism/fixtures/whitequark/send_lambda_args_shadow.txt
new file mode 100644
index 0000000000..230f35ab89
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_lambda_args_shadow.txt
@@ -0,0 +1 @@
+->(a; foo, bar) { }
diff --git a/test/prism/fixtures/whitequark/send_lambda_legacy.txt b/test/prism/fixtures/whitequark/send_lambda_legacy.txt
new file mode 100644
index 0000000000..a509407c43
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_lambda_legacy.txt
@@ -0,0 +1 @@
+->{ }
diff --git a/test/prism/fixtures/whitequark/send_op_asgn_conditional.txt b/test/prism/fixtures/whitequark/send_op_asgn_conditional.txt
new file mode 100644
index 0000000000..906088dcd1
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_op_asgn_conditional.txt
@@ -0,0 +1 @@
+a&.b &&= 1
diff --git a/test/prism/fixtures/whitequark/send_plain.txt b/test/prism/fixtures/whitequark/send_plain.txt
new file mode 100644
index 0000000000..ebaf1d18c7
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_plain.txt
@@ -0,0 +1,5 @@
+foo.fun
+
+foo::Fun()
+
+foo::fun
diff --git a/test/prism/fixtures/whitequark/send_plain_cmd.txt b/test/prism/fixtures/whitequark/send_plain_cmd.txt
new file mode 100644
index 0000000000..e3fd63f272
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_plain_cmd.txt
@@ -0,0 +1,5 @@
+foo.fun bar
+
+foo::Fun bar
+
+foo::fun bar
diff --git a/test/prism/fixtures/whitequark/send_self.txt b/test/prism/fixtures/whitequark/send_self.txt
new file mode 100644
index 0000000000..f084b9bca7
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_self.txt
@@ -0,0 +1,5 @@
+fun
+
+fun!
+
+fun(1)
diff --git a/test/prism/fixtures/whitequark/send_self_block.txt b/test/prism/fixtures/whitequark/send_self_block.txt
new file mode 100644
index 0000000000..1cd6703c82
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_self_block.txt
@@ -0,0 +1,7 @@
+fun do end
+
+fun { }
+
+fun() { }
+
+fun(1) { }
diff --git a/test/prism/fixtures/whitequark/send_unary_op.txt b/test/prism/fixtures/whitequark/send_unary_op.txt
new file mode 100644
index 0000000000..73814d199f
--- /dev/null
+++ b/test/prism/fixtures/whitequark/send_unary_op.txt
@@ -0,0 +1,5 @@
++foo
+
+-foo
+
+~foo
diff --git a/test/prism/fixtures/whitequark/slash_newline_in_heredocs.txt b/test/prism/fixtures/whitequark/slash_newline_in_heredocs.txt
new file mode 100644
index 0000000000..4962a058ea
--- /dev/null
+++ b/test/prism/fixtures/whitequark/slash_newline_in_heredocs.txt
@@ -0,0 +1,13 @@
+<<-E
+ 1 \
+ 2
+ 3
+E
+
+
+<<~E
+ 1 \
+ 2
+ 3
+E
+
diff --git a/test/prism/fixtures/whitequark/space_args_arg.txt b/test/prism/fixtures/whitequark/space_args_arg.txt
new file mode 100644
index 0000000000..47957cba54
--- /dev/null
+++ b/test/prism/fixtures/whitequark/space_args_arg.txt
@@ -0,0 +1 @@
+fun (1)
diff --git a/test/prism/fixtures/whitequark/space_args_arg_block.txt b/test/prism/fixtures/whitequark/space_args_arg_block.txt
new file mode 100644
index 0000000000..5560a82818
--- /dev/null
+++ b/test/prism/fixtures/whitequark/space_args_arg_block.txt
@@ -0,0 +1,5 @@
+foo.fun (1) {}
+
+foo::fun (1) {}
+
+fun (1) {}
diff --git a/test/prism/fixtures/whitequark/space_args_arg_call.txt b/test/prism/fixtures/whitequark/space_args_arg_call.txt
new file mode 100644
index 0000000000..3b0ae831fe
--- /dev/null
+++ b/test/prism/fixtures/whitequark/space_args_arg_call.txt
@@ -0,0 +1 @@
+fun (1).to_i
diff --git a/test/prism/fixtures/whitequark/space_args_arg_newline.txt b/test/prism/fixtures/whitequark/space_args_arg_newline.txt
new file mode 100644
index 0000000000..a6cdac6ed1
--- /dev/null
+++ b/test/prism/fixtures/whitequark/space_args_arg_newline.txt
@@ -0,0 +1,2 @@
+fun (1
+)
diff --git a/test/prism/fixtures/whitequark/space_args_block.txt b/test/prism/fixtures/whitequark/space_args_block.txt
new file mode 100644
index 0000000000..555a097605
--- /dev/null
+++ b/test/prism/fixtures/whitequark/space_args_block.txt
@@ -0,0 +1 @@
+fun () {}
diff --git a/test/prism/fixtures/whitequark/space_args_cmd.txt b/test/prism/fixtures/whitequark/space_args_cmd.txt
new file mode 100644
index 0000000000..a749695cb7
--- /dev/null
+++ b/test/prism/fixtures/whitequark/space_args_cmd.txt
@@ -0,0 +1 @@
+fun (f bar)
diff --git a/test/prism/fixtures/whitequark/string___FILE__.txt b/test/prism/fixtures/whitequark/string___FILE__.txt
new file mode 100644
index 0000000000..4815727d05
--- /dev/null
+++ b/test/prism/fixtures/whitequark/string___FILE__.txt
@@ -0,0 +1 @@
+__FILE__
diff --git a/test/prism/fixtures/whitequark/string_concat.txt b/test/prism/fixtures/whitequark/string_concat.txt
new file mode 100644
index 0000000000..30cc4f8116
--- /dev/null
+++ b/test/prism/fixtures/whitequark/string_concat.txt
@@ -0,0 +1 @@
+"foo#@a" "bar"
diff --git a/test/prism/fixtures/whitequark/string_dvar.txt b/test/prism/fixtures/whitequark/string_dvar.txt
new file mode 100644
index 0000000000..bbe5b617b2
--- /dev/null
+++ b/test/prism/fixtures/whitequark/string_dvar.txt
@@ -0,0 +1 @@
+"#@a #@@a #$a"
diff --git a/test/prism/fixtures/whitequark/string_interp.txt b/test/prism/fixtures/whitequark/string_interp.txt
new file mode 100644
index 0000000000..5fdd803341
--- /dev/null
+++ b/test/prism/fixtures/whitequark/string_interp.txt
@@ -0,0 +1 @@
+"foo#{bar}baz"
diff --git a/test/prism/fixtures/whitequark/string_plain.txt b/test/prism/fixtures/whitequark/string_plain.txt
new file mode 100644
index 0000000000..4aca78decb
--- /dev/null
+++ b/test/prism/fixtures/whitequark/string_plain.txt
@@ -0,0 +1,3 @@
+%q(foobar)
+
+'foobar'
diff --git a/test/prism/fixtures/whitequark/super.txt b/test/prism/fixtures/whitequark/super.txt
new file mode 100644
index 0000000000..9e68a9e988
--- /dev/null
+++ b/test/prism/fixtures/whitequark/super.txt
@@ -0,0 +1,5 @@
+super foo
+
+super()
+
+super(foo)
diff --git a/test/prism/fixtures/whitequark/super_block.txt b/test/prism/fixtures/whitequark/super_block.txt
new file mode 100644
index 0000000000..05a7d7fdd8
--- /dev/null
+++ b/test/prism/fixtures/whitequark/super_block.txt
@@ -0,0 +1,3 @@
+super do end
+
+super foo, bar do end
diff --git a/test/prism/fixtures/whitequark/symbol_interp.txt b/test/prism/fixtures/whitequark/symbol_interp.txt
new file mode 100644
index 0000000000..d5011b270d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/symbol_interp.txt
@@ -0,0 +1 @@
+:"foo#{bar}baz"
diff --git a/test/prism/fixtures/whitequark/symbol_plain.txt b/test/prism/fixtures/whitequark/symbol_plain.txt
new file mode 100644
index 0000000000..fd1fd0017c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/symbol_plain.txt
@@ -0,0 +1,3 @@
+:'foo'
+
+:foo
diff --git a/test/prism/fixtures/whitequark/ternary.txt b/test/prism/fixtures/whitequark/ternary.txt
new file mode 100644
index 0000000000..3a149d4e1c
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ternary.txt
@@ -0,0 +1 @@
+foo ? 1 : 2
diff --git a/test/prism/fixtures/whitequark/ternary_ambiguous_symbol.txt b/test/prism/fixtures/whitequark/ternary_ambiguous_symbol.txt
new file mode 100644
index 0000000000..19aa523c07
--- /dev/null
+++ b/test/prism/fixtures/whitequark/ternary_ambiguous_symbol.txt
@@ -0,0 +1 @@
+t=1;(foo)?t:T
diff --git a/test/prism/fixtures/whitequark/trailing_forward_arg.txt b/test/prism/fixtures/whitequark/trailing_forward_arg.txt
new file mode 100644
index 0000000000..043870ade2
--- /dev/null
+++ b/test/prism/fixtures/whitequark/trailing_forward_arg.txt
@@ -0,0 +1 @@
+def foo(a, b, ...); bar(a, 42, ...); end
diff --git a/test/prism/fixtures/whitequark/true.txt b/test/prism/fixtures/whitequark/true.txt
new file mode 100644
index 0000000000..27ba77ddaf
--- /dev/null
+++ b/test/prism/fixtures/whitequark/true.txt
@@ -0,0 +1 @@
+true
diff --git a/test/prism/fixtures/whitequark/unary_num_pow_precedence.txt b/test/prism/fixtures/whitequark/unary_num_pow_precedence.txt
new file mode 100644
index 0000000000..f0343e3c8b
--- /dev/null
+++ b/test/prism/fixtures/whitequark/unary_num_pow_precedence.txt
@@ -0,0 +1,5 @@
++2.0 ** 10
+
+-2 ** 10
+
+-2.0 ** 10
diff --git a/test/prism/fixtures/whitequark/undef.txt b/test/prism/fixtures/whitequark/undef.txt
new file mode 100644
index 0000000000..3e88ec7084
--- /dev/null
+++ b/test/prism/fixtures/whitequark/undef.txt
@@ -0,0 +1 @@
+undef foo, :bar, :"foo#{1}"
diff --git a/test/prism/fixtures/whitequark/unless.txt b/test/prism/fixtures/whitequark/unless.txt
new file mode 100644
index 0000000000..d04043ed90
--- /dev/null
+++ b/test/prism/fixtures/whitequark/unless.txt
@@ -0,0 +1,3 @@
+unless foo then bar; end
+
+unless foo; bar; end
diff --git a/test/prism/fixtures/whitequark/unless_else.txt b/test/prism/fixtures/whitequark/unless_else.txt
new file mode 100644
index 0000000000..8243d42031
--- /dev/null
+++ b/test/prism/fixtures/whitequark/unless_else.txt
@@ -0,0 +1,3 @@
+unless foo then bar; else baz; end
+
+unless foo; bar; else baz; end
diff --git a/test/prism/fixtures/whitequark/unless_mod.txt b/test/prism/fixtures/whitequark/unless_mod.txt
new file mode 100644
index 0000000000..2d0376a310
--- /dev/null
+++ b/test/prism/fixtures/whitequark/unless_mod.txt
@@ -0,0 +1 @@
+bar unless foo
diff --git a/test/prism/fixtures/whitequark/until.txt b/test/prism/fixtures/whitequark/until.txt
new file mode 100644
index 0000000000..06082233cb
--- /dev/null
+++ b/test/prism/fixtures/whitequark/until.txt
@@ -0,0 +1,3 @@
+until foo do meth end
+
+until foo; meth end
diff --git a/test/prism/fixtures/whitequark/until_mod.txt b/test/prism/fixtures/whitequark/until_mod.txt
new file mode 100644
index 0000000000..46a85d2ba9
--- /dev/null
+++ b/test/prism/fixtures/whitequark/until_mod.txt
@@ -0,0 +1 @@
+meth until foo
diff --git a/test/prism/fixtures/whitequark/until_post.txt b/test/prism/fixtures/whitequark/until_post.txt
new file mode 100644
index 0000000000..988e43b665
--- /dev/null
+++ b/test/prism/fixtures/whitequark/until_post.txt
@@ -0,0 +1 @@
+begin meth end until foo
diff --git a/test/prism/fixtures/whitequark/var_and_asgn.txt b/test/prism/fixtures/whitequark/var_and_asgn.txt
new file mode 100644
index 0000000000..25502968f9
--- /dev/null
+++ b/test/prism/fixtures/whitequark/var_and_asgn.txt
@@ -0,0 +1 @@
+a &&= 1
diff --git a/test/prism/fixtures/whitequark/var_op_asgn.txt b/test/prism/fixtures/whitequark/var_op_asgn.txt
new file mode 100644
index 0000000000..402d818a7e
--- /dev/null
+++ b/test/prism/fixtures/whitequark/var_op_asgn.txt
@@ -0,0 +1,7 @@
+@@var |= 10
+
+@a |= 1
+
+a += 1
+
+def a; @@var |= 10; end
diff --git a/test/prism/fixtures/whitequark/var_op_asgn_cmd.txt b/test/prism/fixtures/whitequark/var_op_asgn_cmd.txt
new file mode 100644
index 0000000000..33f4bc0e73
--- /dev/null
+++ b/test/prism/fixtures/whitequark/var_op_asgn_cmd.txt
@@ -0,0 +1 @@
+foo += m foo
diff --git a/test/prism/fixtures/whitequark/var_or_asgn.txt b/test/prism/fixtures/whitequark/var_or_asgn.txt
new file mode 100644
index 0000000000..aa30b3d5ca
--- /dev/null
+++ b/test/prism/fixtures/whitequark/var_or_asgn.txt
@@ -0,0 +1 @@
+a ||= 1
diff --git a/test/prism/fixtures/whitequark/when_multi.txt b/test/prism/fixtures/whitequark/when_multi.txt
new file mode 100644
index 0000000000..b4fbd33125
--- /dev/null
+++ b/test/prism/fixtures/whitequark/when_multi.txt
@@ -0,0 +1 @@
+case foo; when 'bar', 'baz'; bar; end
diff --git a/test/prism/fixtures/whitequark/when_splat.txt b/test/prism/fixtures/whitequark/when_splat.txt
new file mode 100644
index 0000000000..695e5da34e
--- /dev/null
+++ b/test/prism/fixtures/whitequark/when_splat.txt
@@ -0,0 +1 @@
+case foo; when 1, *baz; bar; when *foo; end
diff --git a/test/prism/fixtures/whitequark/when_then.txt b/test/prism/fixtures/whitequark/when_then.txt
new file mode 100644
index 0000000000..63293452b3
--- /dev/null
+++ b/test/prism/fixtures/whitequark/when_then.txt
@@ -0,0 +1 @@
+case foo; when 'bar' then bar; end
diff --git a/test/prism/fixtures/whitequark/while.txt b/test/prism/fixtures/whitequark/while.txt
new file mode 100644
index 0000000000..28b204f247
--- /dev/null
+++ b/test/prism/fixtures/whitequark/while.txt
@@ -0,0 +1,3 @@
+while foo do meth end
+
+while foo; meth end
diff --git a/test/prism/fixtures/whitequark/while_mod.txt b/test/prism/fixtures/whitequark/while_mod.txt
new file mode 100644
index 0000000000..ce3cf01d14
--- /dev/null
+++ b/test/prism/fixtures/whitequark/while_mod.txt
@@ -0,0 +1 @@
+meth while foo
diff --git a/test/prism/fixtures/whitequark/while_post.txt b/test/prism/fixtures/whitequark/while_post.txt
new file mode 100644
index 0000000000..ac6e05008b
--- /dev/null
+++ b/test/prism/fixtures/whitequark/while_post.txt
@@ -0,0 +1 @@
+begin meth end while foo
diff --git a/test/prism/fixtures/whitequark/xstring_interp.txt b/test/prism/fixtures/whitequark/xstring_interp.txt
new file mode 100644
index 0000000000..dfede8123f
--- /dev/null
+++ b/test/prism/fixtures/whitequark/xstring_interp.txt
@@ -0,0 +1 @@
+`foo#{bar}baz`
diff --git a/test/prism/fixtures/whitequark/xstring_plain.txt b/test/prism/fixtures/whitequark/xstring_plain.txt
new file mode 100644
index 0000000000..fce255049d
--- /dev/null
+++ b/test/prism/fixtures/whitequark/xstring_plain.txt
@@ -0,0 +1 @@
+`foobar`
diff --git a/test/prism/fixtures/whitequark/zsuper.txt b/test/prism/fixtures/whitequark/zsuper.txt
new file mode 100644
index 0000000000..16f5c2d3aa
--- /dev/null
+++ b/test/prism/fixtures/whitequark/zsuper.txt
@@ -0,0 +1 @@
+super
diff --git a/test/prism/fixtures/write_command_operator.txt b/test/prism/fixtures/write_command_operator.txt
new file mode 100644
index 0000000000..d719d24f87
--- /dev/null
+++ b/test/prism/fixtures/write_command_operator.txt
@@ -0,0 +1,3 @@
+foo = 123 | '456' or return
+
+foo = 123 | '456' in BAR
diff --git a/test/prism/fixtures/xstring.txt b/test/prism/fixtures/xstring.txt
new file mode 100644
index 0000000000..465a14e84b
--- /dev/null
+++ b/test/prism/fixtures/xstring.txt
@@ -0,0 +1,21 @@
+%x[foo]
+
+`foo #{bar} baz`
+
+`foo`
+
+%x{
+ foo
+}
+
+``
+
+%x{}
+
+`
+foo\
+b\nar
+`
+
+`
+’`
diff --git a/test/prism/fixtures/xstring_with_backslash.txt b/test/prism/fixtures/xstring_with_backslash.txt
new file mode 100644
index 0000000000..b51bb0f6f9
--- /dev/null
+++ b/test/prism/fixtures/xstring_with_backslash.txt
@@ -0,0 +1 @@
+`f\oo`
diff --git a/test/prism/fixtures/yield.txt b/test/prism/fixtures/yield.txt
new file mode 100644
index 0000000000..752ba27a2e
--- /dev/null
+++ b/test/prism/fixtures/yield.txt
@@ -0,0 +1,7 @@
+def foo; yield; end
+
+def foo; yield(); end
+
+def foo; yield(1); end
+
+def foo; yield(1, 2, 3); end
diff --git a/test/prism/fixtures_test.rb b/test/prism/fixtures_test.rb
new file mode 100644
index 0000000000..dcbcb7c117
--- /dev/null
+++ b/test/prism/fixtures_test.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+return if RUBY_VERSION < "3.2.0"
+
+require_relative "test_helper"
+
+module Prism
+ class FixturesTest < TestCase
+ except = []
+
+ if RUBY_VERSION < "3.3.0"
+ # Ruby < 3.3.0 cannot parse heredocs where there are leading whitespace
+ # characters in the heredoc start.
+ # Example: <<~' EOF' or <<-' EOF'
+ # https://bugs.ruby-lang.org/issues/19539
+ except << "heredocs_leading_whitespace.txt"
+ except << "whitequark/ruby_bug_19539.txt"
+
+ # https://bugs.ruby-lang.org/issues/19025
+ except << "whitequark/numparam_ruby_bug_19025.txt"
+ # https://bugs.ruby-lang.org/issues/18878
+ except << "whitequark/ruby_bug_18878.txt"
+ # https://bugs.ruby-lang.org/issues/19281
+ except << "whitequark/ruby_bug_19281.txt"
+ end
+
+ # https://bugs.ruby-lang.org/issues/21168#note-5
+ except << "command_method_call_2.txt"
+ # https://bugs.ruby-lang.org/issues/21669
+ except << "4.1/void_value.txt"
+ # https://bugs.ruby-lang.org/issues/19107
+ except << "4.1/trailing_comma_after_method_arguments.txt"
+
+ Fixture.each_for_current_ruby(except: except) do |fixture|
+ define_method(fixture.test_name) { assert_valid_syntax(fixture.read) }
+ end
+ end
+end
diff --git a/test/prism/fuzzer_test.rb b/test/prism/fuzzer_test.rb
new file mode 100644
index 0000000000..4927478bdc
--- /dev/null
+++ b/test/prism/fuzzer_test.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+require_relative "test_helper"
+
+module Prism
+ # These tests are simply to exercise snippets found by the fuzzer that caused
+ # invalid memory access.
+ class FuzzerTest < TestCase
+ def self.snippet(name, source)
+ define_method(:"test_fuzzer_#{name}") { Prism.profile(source) }
+ end
+
+ snippet "incomplete global variable", "$"
+ snippet "incomplete symbol", ":"
+ snippet "incomplete escaped string", '"\\'
+ snippet "trailing comment", "1\n#\n"
+ snippet "comment followed by whitespace at end of file", "1\n#\n "
+ snippet "trailing asterisk", "a *"
+ snippet "incomplete decimal number", "0d"
+ snippet "incomplete binary number", "0b"
+ snippet "incomplete octal number", "0o"
+ snippet "incomplete hex number", "0x"
+ snippet "incomplete escaped list", "%w[\\"
+ snippet "incomplete escaped regex", "/a\\"
+ snippet "unterminated heredoc with unterminated escape at end of file", "<<A\n\\"
+ snippet "escaped octal at end of file 1", '"\\3'
+ snippet "escaped octal at end of file 2", '"\\33'
+ snippet "escaped hex at end of file 1", '"\\x'
+ snippet "escaped hex at end of file 2", '"\\x3'
+ snippet "escaped unicode at end of file 1", '"\\u{3'
+ snippet "escaped unicode at end of file 2", '"\\u{33'
+ snippet "escaped unicode at end of file 3", '"\\u{333'
+ snippet "escaped unicode at end of file 4", '"\\u{3333'
+ snippet "escaped unicode at end of file 5", '"\\u{33333'
+ snippet "escaped unicode at end of file 6", '"\\u{333333'
+ snippet "escaped unicode at end of file 7", '"\\u3'
+ snippet "escaped unicode at end of file 8", '"\\u33'
+ snippet "escaped unicode at end of file 9", '"\\u333'
+ snippet "float suffix at end of file", "1e"
+ snippet "parameter name that is zero length", "a { |b;"
+
+ snippet "statements node with multiple heredocs", <<~EOF
+ for <<A + <<B
+ A
+ B
+ EOF
+
+ snippet "create a binary call node with arg before receiver", <<~EOF
+ <<-A.g/{/
+ A
+ /, ""\\
+ EOF
+
+ snippet "regular expression with start and end out of order", <<~RUBY
+ <<-A.g//,
+ A
+ /{/, ''\\
+ RUBY
+
+ snippet "interpolated regular expression with start and end out of order", <<~RUBY
+ <<-A.g/{/,
+ A
+ a
+ /{/, ''\\
+ RUBY
+ end
+end
diff --git a/test/prism/heredoc_dedent_test.rb b/test/prism/heredoc_dedent_test.rb
new file mode 100644
index 0000000000..4e7a3c0a14
--- /dev/null
+++ b/test/prism/heredoc_dedent_test.rb
@@ -0,0 +1,134 @@
+# frozen_string_literal: true
+
+require_relative "test_helper"
+
+module Prism
+ class HeredocDedentTest < TestCase
+ def test_content_dedented_interpolation_content
+ assert_heredoc_dedent(
+ " a\n" "1\n" " a\n",
+ "<<~EOF\n" " a\n" "\#{1}\n" " a\n" "EOF\n"
+ )
+ end
+
+ def test_content
+ assert_heredoc_dedent(
+ "a\n",
+ "<<~EOF\n" " a\n" "EOF\n"
+ )
+ end
+
+ def test_tabs_dedent_spaces
+ assert_heredoc_dedent(
+ "\ta\n" "b\n" "\t\tc\n",
+ "<<~EOF\n" "\ta\n" " b\n" "\t\tc\n" "EOF\n"
+ )
+ end
+
+ def test_interpolation_then_content
+ assert_heredoc_dedent(
+ "1 a\n",
+ "<<~EOF\n" " \#{1} a\n" "EOF\n"
+ )
+ end
+
+ def test_content_then_interpolation
+ assert_heredoc_dedent(
+ "a 1\n",
+ "<<~EOF\n" " a \#{1}\n" "EOF\n"
+ )
+ end
+
+ def test_content_dedented_interpolation
+ assert_heredoc_dedent(
+ " a\n" "1\n",
+ "<<~EOF\n" " a\n" " \#{1}\n" "EOF\n"
+ )
+ end
+
+ def test_content_interpolation
+ assert_heredoc_dedent(
+ "a\n" "1\n",
+ "<<~EOF\n" " a\n" " \#{1}\n" "EOF\n"
+ )
+ end
+
+ def test_content_content
+ assert_heredoc_dedent(
+ "a\n" "b\n",
+ "<<~EOF\n" " a\n" " b\n" "EOF\n"
+ )
+ end
+
+ def test_content_indented_content
+ assert_heredoc_dedent(
+ "a\n" " b\n",
+ "<<~EOF\n" " a\n" " b\n" "EOF\n"
+ )
+ end
+
+ def test_content_dedented_content
+ assert_heredoc_dedent(
+ "\ta\n" "b\n",
+ "<<~EOF\n" "\t\t\ta\n" "\t\tb\n" "EOF\n"
+ )
+ end
+
+ def test_single_quote
+ assert_heredoc_dedent(
+ "a \#{1}\n",
+ "<<~'EOF'\n" "a \#{1}\n" "EOF\n"
+ )
+ end
+
+ def test_mixed_indentation
+ assert_heredoc_dedent(
+ "a\n" " b\n",
+ "<<~EOF\n" "\ta\n" "\t b\n" "EOF\n"
+ )
+ end
+
+ def test_indented_content_content
+ assert_heredoc_dedent(
+ " a\n" "b\n",
+ "<<~EOF\n" "\t a\n" "\tb\n" "EOF\n"
+ )
+ end
+
+ def test_indent_size
+ assert_heredoc_dedent(
+ "a\n" " b\n",
+ "<<~EOF\n" "\ta\n" " b\n" "EOF\n"
+ )
+ end
+
+ def test_blank_lines
+ assert_heredoc_dedent(
+ "a\n" "\n" "b\n",
+ "<<~EOF\n" " a\n" "\n" " b\n" "EOF\n"
+ )
+ end
+
+ def test_many_blank_lines
+ assert_heredoc_dedent(
+ "a\n" "\n" "\n" "\n" "\n" "b\n",
+ "<<~EOF\n" " a\n" "\n" "\n" "\n" "\n" " b\n" "EOF\n"
+ )
+ end
+
+ private
+
+ def assert_heredoc_dedent(expected, source)
+ node = Prism.parse_statement(source)
+
+ if node.is_a?(StringNode)
+ actual = node.unescaped
+ else
+ actual = node.parts.map { |part| part.is_a?(StringNode) ? part.unescaped : "1" }.join
+ end
+
+ assert_equal(expected, actual)
+ assert_equal(eval(source), actual)
+ end
+ end
+end
diff --git a/test/prism/lex_test.rb b/test/prism/lex_test.rb
new file mode 100644
index 0000000000..1e06d52184
--- /dev/null
+++ b/test/prism/lex_test.rb
@@ -0,0 +1,123 @@
+# frozen_string_literal: true
+
+return if !(RUBY_ENGINE == "ruby" && RUBY_VERSION >= "3.2.0")
+
+require_relative "test_helper"
+require "ripper"
+
+module Prism
+ class LexTest < TestCase
+ def test_lex_file
+ assert_nothing_raised do
+ Prism.lex_file(__FILE__)
+ end
+
+ error = assert_raise Errno::ENOENT do
+ Prism.lex_file("idontexist.rb")
+ end
+
+ assert_equal "No such file or directory - idontexist.rb", error.message
+
+ assert_raise TypeError do
+ Prism.lex_file(nil)
+ end
+ end
+
+ def test_parse_lex
+ node, tokens = Prism.parse_lex("def foo; end").value
+
+ assert_kind_of ProgramNode, node
+ assert_equal 5, tokens.length
+ end
+
+ def test_parse_lex_file
+ node, tokens = Prism.parse_lex_file(__FILE__).value
+
+ assert_kind_of ProgramNode, node
+ refute_empty tokens
+
+ error = assert_raise Errno::ENOENT do
+ Prism.parse_lex_file("idontexist.rb")
+ end
+
+ assert_equal "No such file or directory - idontexist.rb", error.message
+
+ assert_raise TypeError do
+ Prism.parse_lex_file(nil)
+ end
+ end
+
+ def test_lex_encoding
+ tokens = Prism.lex('"わたし"', encoding: Encoding::Windows_31J).value
+ tokens.each do |t|
+ assert_equal(Encoding::Windows_31J, t[0].value.encoding)
+ end
+
+ # Shebangs must appear on the first line. For these cases, the encoding
+ # comment may appear second, but it should still change encoding.
+ tokens = Prism.lex(<<~RUBY, encoding: Encoding::Windows_31J).value
+ #! /usr/bin/env ruby
+ # encoding: utf-8
+ "わたし"
+ RUBY
+ tokens.each do |t|
+ assert_equal(Encoding::UTF_8, t[0].value.encoding)
+ end
+ end
+
+ if RUBY_VERSION >= "3.3"
+ def test_lex_compat
+ source = "foo bar"
+ prism = Prism.lex_compat(source, version: "current").value
+ ripper = Ripper.lex(source)
+ assert_equal(ripper, prism)
+ end
+ end
+
+ def test_lex_interpolation_unterminated
+ assert_equal(
+ %i[STRING_BEGIN EMBEXPR_BEGIN EOF],
+ token_types('"#{')
+ )
+
+ assert_equal(
+ %i[STRING_BEGIN EMBEXPR_BEGIN IGNORED_NEWLINE EOF],
+ token_types('"#{' + "\n")
+ )
+ end
+
+ def test_lex_interpolation_unterminated_with_content
+ # FIXME: Emits EOL twice.
+ assert_equal(
+ %i[STRING_BEGIN EMBEXPR_BEGIN CONSTANT EOF EOF],
+ token_types('"#{C')
+ )
+
+ assert_equal(
+ %i[STRING_BEGIN EMBEXPR_BEGIN CONSTANT NEWLINE EOF],
+ token_types('"#{C' + "\n")
+ )
+ end
+
+ def test_lex_heredoc_unterminated
+ code = <<~'RUBY'.strip
+ <<A+B
+ #{C
+ RUBY
+
+ assert_equal(
+ %i[HEREDOC_START EMBEXPR_BEGIN CONSTANT HEREDOC_END PLUS CONSTANT NEWLINE EOF],
+ token_types(code)
+ )
+
+ assert_equal(
+ %i[HEREDOC_START EMBEXPR_BEGIN CONSTANT NEWLINE HEREDOC_END PLUS CONSTANT NEWLINE EOF],
+ token_types(code + "\n")
+ )
+ end
+
+ def token_types(code)
+ Prism.lex(code).value.map { |token, _state| token.type }
+ end
+ end
+end
diff --git a/test/prism/library_symbols_test.rb b/test/prism/library_symbols_test.rb
new file mode 100644
index 0000000000..44f225478b
--- /dev/null
+++ b/test/prism/library_symbols_test.rb
@@ -0,0 +1,104 @@
+# frozen_string_literal: true
+
+require_relative "test_helper"
+
+return if RUBY_PLATFORM !~ /linux/
+return if RUBY_PLATFORM =~ /powerpc64le/
+
+module Prism
+ #
+ # examine a prism dll or static archive for expected external symbols.
+ # these tests only work on a linux system right now.
+ #
+ class LibrarySymbolsTest < TestCase
+ def setup
+ super
+
+ @libprism_a = File.expand_path("../../build/libprism.a", __dir__)
+ @libprism_so = File.expand_path("../../build/libprism.so", __dir__)
+ @prism_so = File.expand_path("../../lib/prism/prism.so", __dir__)
+ end
+
+ # objdump runner and helpers
+ def objdump(path)
+ assert_path_exist(path)
+ %x(objdump --section=.text --syms #{path}).split("\n")
+ end
+
+ def global_objdump_symbols(path)
+ objdump(path).select { |line| line[17] == "g" }
+ end
+
+ def hidden_global_objdump_symbols(path)
+ global_objdump_symbols(path).select { |line| line =~ / \.hidden / }
+ end
+
+ def visible_global_objdump_symbols(path)
+ global_objdump_symbols(path).reject { |line| line =~ / \.hidden / }
+ end
+
+ # nm runner and helpers
+ def nm(path)
+ assert_path_exist(path)
+ %x(nm #{path}).split("\n")
+ end
+
+ def global_nm_symbols(path)
+ nm(path).select { |line| line[17] == "T" }
+ end
+
+ def local_nm_symbols(path)
+ nm(path).select { |line| line[17] == "t" }
+ end
+
+ # dig the symbol name out of each line. works for both `objdump` and `nm` output.
+ def names(symbol_lines)
+ symbol_lines.map { |line| line.split(/\s+/).last }
+ end
+
+ #
+ # static archive - libprism.a
+ #
+ def test_libprism_a_contains_nothing_globally_visible
+ omit("libprism.a is not built") unless File.exist?(@libprism_a)
+
+ assert_empty(names(visible_global_objdump_symbols(@libprism_a)))
+ end
+
+ def test_libprism_a_contains_hidden_pm_symbols
+ omit("libprism.a is not built") unless File.exist?(@libprism_a)
+
+ names(hidden_global_objdump_symbols(@libprism_a)).tap do |symbols|
+ assert_includes(symbols, "pm_parse")
+ assert_includes(symbols, "pm_version")
+ end
+ end
+
+ #
+ # shared object - libprism.so
+ #
+ def test_libprism_so_exports_only_the_necessary_functions
+ omit("libprism.so is not built") unless File.exist?(@libprism_so)
+
+ names(global_nm_symbols(@libprism_so)).tap do |symbols|
+ assert_includes(symbols, "pm_parse")
+ assert_includes(symbols, "pm_version")
+ end
+ names(local_nm_symbols(@libprism_so)).tap do |symbols|
+ assert_includes(symbols, "pm_encoding_utf_8_isupper_char")
+ end
+ # TODO: someone who uses this library needs to finish this test
+ end
+
+ #
+ # shared object - prism.so
+ #
+ def test_prism_so_exports_only_the_C_extension_init_function
+ omit("prism.so is not built") unless File.exist?(@prism_so)
+
+ names(global_nm_symbols(@prism_so)).tap do |symbols|
+ assert_equal(["Init_prism"], symbols)
+ end
+ end
+ end
+end
diff --git a/test/prism/locals_test.rb b/test/prism/locals_test.rb
new file mode 100644
index 0000000000..417730a8a7
--- /dev/null
+++ b/test/prism/locals_test.rb
@@ -0,0 +1,245 @@
+# frozen_string_literal: true
+
+# This test is going to use the RubyVM::InstructionSequence class to compile
+# local tables and compare against them to ensure we have the same locals in the
+# same order. This is important to guarantee that we compile indices correctly
+# on CRuby (in terms of compatibility).
+#
+# There have also been changes made in other versions of Ruby, so we only want
+# to test on the most recent versions.
+return if !defined?(RubyVM::InstructionSequence) || RUBY_VERSION < "3.4.0"
+
+# If we're on Ruby 3.4.0 and the default parser is Prism, then there is no point
+# in comparing the locals because they will be the same.
+return if RubyVM::InstructionSequence.compile("").to_a[4][:parser] == :prism
+
+# Omit tests if running on a 32-bit machine because there is a bug with how
+# Ruby is handling large ISeqs on 32-bit machines
+return if RUBY_PLATFORM =~ /i686/
+
+require_relative "test_helper"
+
+module Prism
+ class LocalsTest < TestCase
+ except = [
+ # Skip this fixture because it has a different number of locals because
+ # CRuby is eliminating dead code.
+ "whitequark/ruby_bug_10653.txt",
+
+ # https://bugs.ruby-lang.org/issues/21168#note-5
+ "command_method_call_2.txt",
+
+ # https://bugs.ruby-lang.org/issues/21669
+ "4.1/void_value.txt",
+
+ # https://bugs.ruby-lang.org/issues/19107
+ "4.1/trailing_comma_after_method_arguments.txt",
+ ]
+
+ Fixture.each_for_current_ruby(except: except) do |fixture|
+ define_method(fixture.test_name) { assert_locals(fixture) }
+ end
+
+ def setup
+ @previous_default_external = Encoding.default_external
+ ignore_warnings { Encoding.default_external = Encoding::UTF_8 }
+ end
+
+ def teardown
+ ignore_warnings { Encoding.default_external = @previous_default_external }
+ end
+
+ private
+
+ def assert_locals(fixture)
+ source = fixture.read
+
+ expected = cruby_locals(source)
+ actual = prism_locals(source)
+
+ assert_equal(expected, actual)
+ end
+
+ # A wrapper around a RubyVM::InstructionSequence that provides a more
+ # convenient interface for accessing parts of the iseq.
+ class ISeq
+ attr_reader :parts
+
+ def initialize(parts)
+ @parts = parts
+ end
+
+ def type
+ parts[0]
+ end
+
+ def local_table
+ parts[10]
+ end
+
+ def instructions
+ parts[13]
+ end
+
+ def each_child
+ instructions.each do |instruction|
+ # Only look at arrays. Other instructions are line numbers or
+ # tracepoint events.
+ next unless instruction.is_a?(Array)
+
+ instruction.each do |opnd|
+ # Only look at arrays. Other operands are literals.
+ next unless opnd.is_a?(Array)
+
+ # Only look at instruction sequences. Other operands are literals.
+ next unless opnd[0] == "YARVInstructionSequence/SimpleDataFormat"
+
+ yield ISeq.new(opnd)
+ end
+ end
+ end
+ end
+
+ # Used to hold the place of a local that will be in the local table but
+ # cannot be accessed directly from the source code. For example, the
+ # iteration variable in a for loop or the positional parameter on a method
+ # definition that is destructured.
+ AnonymousLocal = Object.new
+
+ # For the given source, compiles with CRuby and returns a list of all of the
+ # sets of local variables that were encountered.
+ def cruby_locals(source)
+ locals = [] #: Array[Array[Symbol | Integer]]
+ stack = [ISeq.new(ignore_warnings { RubyVM::InstructionSequence.compile(source) }.to_a)]
+
+ while (iseq = stack.pop)
+ names = [*iseq.local_table]
+ names.map!.with_index do |name, index|
+ # When an anonymous local variable is present in the iseq's local
+ # table, it is represented as the stack offset from the top.
+ # However, when these are dumped to binary and read back in, they
+ # are replaced with the symbol :#arg_rest. To consistently handle
+ # this, we replace them here with their index.
+ if name == :"#arg_rest"
+ names.length - index + 1
+ else
+ name
+ end
+ end
+
+ locals << names
+ iseq.each_child { |child| stack << child }
+ end
+
+ locals
+ end
+
+ # For the given source, parses with prism and returns a list of all of the
+ # sets of local variables that were encountered.
+ def prism_locals(source)
+ locals = [] #: Array[Array[Symbol | Integer]]
+ stack = [Prism.parse(source).value] #: Array[Prism::node]
+
+ while (node = stack.pop)
+ case node
+ when BlockNode, DefNode, LambdaNode
+ names = node.locals
+ params = nil
+
+ if node.is_a?(DefNode)
+ params = node.parameters
+ elsif node.parameters.is_a?(NumberedParametersNode)
+ # nothing
+ elsif node.parameters.is_a?(ItParametersNode)
+ names.unshift(AnonymousLocal)
+ else
+ params = node.parameters&.parameters
+ end
+
+ # prism places parameters in the same order that they appear in the
+ # source. CRuby places them in the order that they need to appear
+ # according to their own internal calling convention. We mimic that
+ # order here so that we can compare properly.
+ if params
+ sorted = [
+ *params.requireds.map do |required|
+ if required.is_a?(RequiredParameterNode)
+ required.name
+ else
+ AnonymousLocal
+ end
+ end,
+ *params.optionals.map(&:name),
+ *((params.rest.name || :*) if params.rest && !params.rest.is_a?(ImplicitRestNode)),
+ *params.posts.map do |post|
+ if post.is_a?(RequiredParameterNode)
+ post.name
+ else
+ AnonymousLocal
+ end
+ end,
+ *params.keywords.grep(RequiredKeywordParameterNode).map(&:name),
+ *params.keywords.grep(OptionalKeywordParameterNode).map(&:name),
+ ]
+
+ sorted << AnonymousLocal if params.keywords.any?
+
+ if params.keyword_rest.is_a?(ForwardingParameterNode)
+ if sorted.length == 0
+ sorted.push(:"...")
+ else
+ sorted.push(:*, :**, :&, :"...")
+ end
+ elsif params.keyword_rest.is_a?(KeywordRestParameterNode)
+ sorted << (params.keyword_rest.name || :**)
+ end
+
+ # Recurse down the parameter tree to find any destructured
+ # parameters and add them after the other parameters.
+ param_stack = params.requireds.concat(params.posts).grep(MultiTargetNode).reverse
+ while (param = param_stack.pop)
+ case param
+ when MultiTargetNode
+ param_stack.concat(param.rights.reverse)
+ param_stack << param.rest if param.rest&.expression && !sorted.include?(param.rest.expression.name)
+ param_stack.concat(param.lefts.reverse)
+ when RequiredParameterNode
+ sorted << param.name
+ when SplatNode
+ sorted << param.expression.name
+ end
+ end
+
+ if params.block.is_a?(BlockParameterNode)
+ sorted << (params.block.name || :&)
+ end
+
+ names = sorted.concat(names - sorted)
+ end
+
+ names.map!.with_index do |name, index|
+ if name == AnonymousLocal
+ names.length - index + 1
+ else
+ name
+ end
+ end
+
+ locals << names
+ when ClassNode, ModuleNode, ProgramNode, SingletonClassNode
+ locals << node.locals
+ when ForNode
+ locals << [2]
+ when PostExecutionNode
+ locals.push([], [])
+ when InterpolatedRegularExpressionNode
+ locals << [] if node.once?
+ end
+
+ stack.concat(node.compact_child_nodes)
+ end
+
+ locals
+ end
+ end
+end
diff --git a/test/prism/magic_comment_test.rb b/test/prism/magic_comment_test.rb
new file mode 100644
index 0000000000..7985bae568
--- /dev/null
+++ b/test/prism/magic_comment_test.rb
@@ -0,0 +1,122 @@
+# frozen_string_literal: true
+
+require_relative "test_helper"
+require "ripper"
+
+module Prism
+ class MagicCommentTest < TestCase
+ if RUBY_ENGINE == "ruby"
+ class MagicCommentRipper < Ripper
+ attr_reader :magic_comments
+
+ def initialize(*)
+ super
+ @magic_comments = []
+ end
+
+ def on_magic_comment(key, value)
+ @magic_comments << [key, value]
+ super
+ end
+ end
+
+ Fixture.each do |fixture|
+ define_method(fixture.test_name) { assert_magic_comments(fixture) }
+ end
+ end
+
+ def test_encoding
+ assert_magic_encoding(Encoding::US_ASCII, "# encoding: ascii")
+ end
+
+ def test_coding
+ assert_magic_encoding(Encoding::US_ASCII, "# coding: ascii")
+ end
+
+ def test_eNcOdInG
+ assert_magic_encoding(Encoding::US_ASCII, "# eNcOdInG: ascii")
+ end
+
+ def test_CoDiNg
+ assert_magic_encoding(Encoding::US_ASCII, "# CoDiNg: ascii")
+ end
+
+ def test_encoding_whitespace
+ assert_magic_encoding(Encoding::US_ASCII, "# \s\t\v encoding \s\t\v : \s\t\v ascii \s\t\v")
+ end
+
+ def test_emacs_encoding
+ assert_magic_encoding(Encoding::US_ASCII, "# -*- encoding: ascii -*-")
+ end
+
+ def test_emacs_coding
+ assert_magic_encoding(Encoding::US_ASCII, "# -*- coding: ascii -*-")
+ end
+
+ def test_emacs_eNcOdInG
+ assert_magic_encoding(Encoding::US_ASCII, "# -*- eNcOdInG: ascii -*-")
+ end
+
+ def test_emacs_CoDiNg
+ assert_magic_encoding(Encoding::US_ASCII, "# -*- CoDiNg: ascii -*-")
+ end
+
+ def test_emacs_whitespace
+ assert_magic_encoding(Encoding::US_ASCII, "# -*- \s\t\v encoding \s\t\v : \s\t\v ascii \s\t\v -*-")
+ end
+
+ def test_emacs_multiple
+ assert_magic_encoding(Encoding::US_ASCII, "# -*- foo: bar; encoding: ascii -*-")
+ end
+
+ def test_emacs_missing_delimiter
+ assert_magic_encoding(Encoding::US_ASCII, '# -*- \1; encoding: ascii -*-')
+ end
+
+ def test_coding_whitespace
+ assert_magic_encoding(Encoding::ASCII_8BIT, "# coding \t \r \v : \t \v \r ascii-8bit")
+ end
+
+ def test_vim
+ assert_magic_encoding(Encoding::Windows_31J, "# vim: filetype=ruby, fileencoding=windows-31j, tabsize=3, shiftwidth=3")
+ end
+
+ private
+
+ def assert_magic_encoding(expected, line)
+ source = %Q{#{line}\n""}
+ actual = Prism.parse(source).encoding
+
+ # Compare against our expectation.
+ assert_equal expected, actual
+
+ # Compare against Ruby's expectation.
+ if defined?(RubyVM::InstructionSequence)
+ previous = $VERBOSE
+ expected =
+ begin
+ $VERBOSE = nil
+ RubyVM::InstructionSequence.compile(source).eval.encoding
+ ensure
+ $VERBOSE = previous
+ end
+ assert_equal expected, actual
+ end
+ end
+
+ def assert_magic_comments(fixture)
+ source = fixture.read
+
+ # Check that we get the correct number of magic comments when lexing with
+ # ripper.
+ expected = MagicCommentRipper.new(source).tap(&:parse).magic_comments
+ actual = Prism.parse(source).magic_comments
+
+ assert_equal expected.length, actual.length
+ expected.zip(actual).each do |(expected_key, expected_value), magic_comment|
+ assert_equal expected_key, magic_comment.key
+ assert_equal expected_value, magic_comment.value
+ end
+ end
+ end
+end
diff --git a/test/prism/newline_offsets_test.rb b/test/prism/newline_offsets_test.rb
new file mode 100644
index 0000000000..bb06876a96
--- /dev/null
+++ b/test/prism/newline_offsets_test.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require_relative "test_helper"
+
+module Prism
+ class NewlineOffsetsTest < TestCase
+ Fixture.each do |fixture|
+ define_method(fixture.test_name) { assert_newline_offsets(fixture) }
+ end
+
+ def test_escape_control_newline
+ # Newlines consumed inside escape sequences like \C-, \c, and \M-
+ # must be tracked in line offsets across all literal types.
+ %w[\\C- \\c \\M-].each do |escape|
+ assert_newline_offsets_for("\"#{escape}\n\"", "#{escape} in string")
+ assert_newline_offsets_for("`#{escape}\n`", "#{escape} in xstring")
+ assert_newline_offsets_for("/#{escape}\n/", "#{escape} in regexp")
+ assert_newline_offsets_for("%Q{#{escape}\n}", "#{escape} in %Q")
+ assert_newline_offsets_for("%W[#{escape}\n]", "#{escape} in %W")
+ assert_newline_offsets_for("<<~H\n#{escape}\n\nH\n", "#{escape} in heredoc")
+ assert_newline_offsets_for("?#{escape}\n", "#{escape} in char literal")
+ end
+
+ # Combined meta + control escapes
+ assert_newline_offsets_for("\"\\M-\\C-\n\"", "\\M-\\C- in string")
+ assert_newline_offsets_for("\"\\M-\\c\n\"", "\\M-\\c in string")
+
+ # \r\n consumed inside escape context
+ assert_newline_offsets_for("\"\\C-\r\n\"", "\\C- with \\r\\n")
+ end
+
+ private
+
+ def assert_newline_offsets(fixture)
+ assert_newline_offsets_for(fixture.read)
+ end
+
+ def assert_newline_offsets_for(source, message = nil)
+ expected = [0]
+ source.b.scan("\n") { expected << $~.offset(0)[0] + 1 }
+
+ assert_equal expected, Prism.parse(source).source.offsets, message
+ end
+ end
+end
diff --git a/test/prism/newline_test.rb b/test/prism/newline_test.rb
new file mode 100644
index 0000000000..97e698202d
--- /dev/null
+++ b/test/prism/newline_test.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+require_relative "test_helper"
+
+return unless defined?(RubyVM::InstructionSequence)
+
+module Prism
+ class NewlineTest < TestCase
+ skips = %w[
+ errors_test.rb
+ locals_test.rb
+ regexp_test.rb
+ test_helper.rb
+ unescape_test.rb
+ encoding/regular_expression_encoding_test.rb
+ encoding/string_encoding_test.rb
+ result/breadth_first_search_test.rb
+ result/static_literals_test.rb
+ result/warnings_test.rb
+ ruby/find_fixtures.rb
+ ruby/find_test.rb
+ ruby/parser_test.rb
+ ruby/ripper_test.rb
+ ruby/ruby_parser_test.rb
+ ]
+
+ base = __dir__
+ (Dir["{,api/,encoding/,result/,ruby/}*.rb", base: base] - skips).each do |relative|
+ define_method(:"test_#{relative}") do
+ assert_newlines(base, relative)
+ end
+ end
+
+ private
+
+ def assert_newlines(base, relative)
+ filepath = File.join(base, relative)
+ source = File.read(filepath, binmode: true, external_encoding: Encoding::UTF_8)
+ expected = rubyvm_lines(source)
+
+ result = Prism.parse_file(filepath)
+ assert_empty result.errors
+ actual = prism_lines(result)
+
+ source.each_line.with_index(1) do |line, line_number|
+ # Lines like `while (foo = bar)` result in two line flags in the
+ # bytecode but only one newline flag in the AST. We need to remove the
+ # extra line flag from the bytecode to make the test pass.
+ if line.match?(/while \(/)
+ index = expected.index(line_number)
+ expected.delete_at(index) if index
+ end
+
+ # Lines like `foo =` where the value is on the next line result in
+ # another line flag in the bytecode but only one newline flag in the
+ # AST.
+ if line.match?(/^\s+\w+ =$/)
+ if source.lines[line_number].match?(/^\s+case/)
+ actual[actual.index(line_number)] += 1
+ else
+ actual.delete_at(actual.index(line_number))
+ end
+ end
+
+ if line.match?(/^\s+\w+ = \[$/)
+ if !expected.include?(line_number) && !expected.include?(line_number + 2)
+ actual[actual.index(line_number)] += 1
+ end
+ end
+ end
+
+ assert_equal expected, actual
+ end
+
+ def rubyvm_lines(source)
+ queue = [ignore_warnings { RubyVM::InstructionSequence.compile(source) }]
+ lines = []
+
+ while iseq = queue.shift
+ lines.concat(iseq.trace_points.filter_map { |line, event| line if event == :line })
+ iseq.each_child { |insn| queue << insn unless insn.label.start_with?("ensure in ") }
+ end
+
+ lines.sort
+ end
+
+ def prism_lines(result)
+ result.mark_newlines!
+
+ queue = [result.value]
+ newlines = []
+
+ while node = queue.shift
+ queue.concat(node.compact_child_nodes)
+ newlines << result.source.line(node.location.start_offset) if node&.newline_flag?
+ end
+
+ newlines.sort
+ end
+ end
+end
diff --git a/test/prism/onigmo_test.rb b/test/prism/onigmo_test.rb
new file mode 100644
index 0000000000..03f44c4e4c
--- /dev/null
+++ b/test/prism/onigmo_test.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+return if RUBY_ENGINE != "ruby"
+
+require_relative "test_helper"
+
+begin
+ require "onigmo"
+rescue LoadError
+ # In CRuby's CI, we're not going to test against the parser gem because we
+ # don't want to have to install it. So in this case we'll just skip this test.
+ return
+end
+
+module Prism
+ class OnigmoTest < TestCase
+ def test_ONIGERR_PARSE_DEPTH_LIMIT_OVER
+ assert_error(%Q{#{"(" * 4096}a#{")" * 4096}}, "parse depth limit over")
+ end
+
+ def test_ONIGERR_EMPTY_CHAR_CLASS
+ assert_error("[]", "empty char-class")
+ end
+
+ def test_ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED
+ assert_error("*", "target of repeat operator is not specified")
+ assert_error("+", "target of repeat operator is not specified")
+ assert_error("?", "target of repeat operator is not specified")
+ end
+
+ def test_ONIGERR_EMPTY_GROUP_NAME
+ assert_error("(?<>)", "group name is empty")
+ end
+
+ def test_ONIGERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS
+ assert_error("(", "end pattern with unmatched parenthesis")
+ assert_error("(|", "end pattern with unmatched parenthesis")
+ assert_error("(?<", "end pattern with unmatched parenthesis")
+ end
+
+ def test_ONIGERR_END_PATTERN_IN_GROUP
+ assert_error("(?", "end pattern in group")
+ assert_error("(?#", "end pattern in group")
+ end
+
+ def test_ONIGERR_UNDEFINED_GROUP_OPTION
+ assert_error("(?P", "undefined group option")
+ end
+
+ def test_ONIGERR_UNMATCHED_CLOSE_PARENTHESIS
+ assert_error(")", "unmatched close parenthesis")
+ end
+
+ private
+
+ def assert_error(source, message)
+ result = Prism.parse("/#{source}/")
+
+ assert result.failure?, "Expected #{source.inspect} to error"
+ assert_equal message, result.errors.first.message
+
+ error = assert_raise(ArgumentError) { Onigmo.parse(source) }
+ assert_equal message, error.message
+ end
+ end
+end
diff --git a/test/prism/percent_delimiter_string_test.rb b/test/prism/percent_delimiter_string_test.rb
new file mode 100644
index 0000000000..6fd825ad06
--- /dev/null
+++ b/test/prism/percent_delimiter_string_test.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+require_relative "test_helper"
+
+module Prism
+ module PercentDelimiterTests
+ def test_newline_terminator_with_lf_crlf
+ str = l "\n123456\r\n"
+ assert_parse "123456", str
+ end
+
+ def test_newline_terminator_with_lf_crlf_with_extra_cr
+ str = l "\n123456\r\r\n"
+ assert_parse "123456\r", str
+ end
+
+ def test_newline_terminator_with_crlf_pair
+ str = l "\r\n123456\r\n"
+ assert_parse "123456", str
+ end
+
+ def test_newline_terminator_with_crlf_crlf_with_extra_cr
+ str = l "\r\n123456\r\r\n"
+ assert_parse "123456\r", str
+ end
+
+ def test_newline_terminator_with_cr_cr
+ str = l "\r123456\r;\n"
+ assert_parse "123456", str
+ end
+
+ def test_newline_terminator_with_crlf_lf
+ str = l "\r\n123456\n;\n"
+ assert_parse "123456", str
+ end
+
+ def test_cr_crlf
+ str = l "\r1\r\n \r"
+ assert_parse "1\n ", str
+ end
+
+ def test_lf_crlf
+ str = l "\n1\r\n \n"
+ assert_parse "1", str
+ end
+
+ def test_lf_lf
+ str = l "\n1\n \n"
+ assert_parse "1", str
+ end
+
+ def assert_parse(expected, str)
+ assert_equal expected, find_node(str).unescaped
+ end
+ end
+
+ class PercentDelimiterStringTest < TestCase
+ include PercentDelimiterTests
+
+ def find_node(str)
+ tree = Prism.parse str
+ tree.value.breadth_first_search { |x| Prism::StringNode === x }
+ end
+
+ def l(str)
+ "%" + str
+ end
+ end
+
+ class PercentDelimiterRegexpTest < TestCase
+ include PercentDelimiterTests
+
+ def l(str)
+ "%r" + str
+ end
+
+ def find_node(str)
+ tree = Prism.parse str
+ tree.value.breadth_first_search { |x| Prism::RegularExpressionNode === x }
+ end
+ end
+end
diff --git a/test/prism/ractor_test.rb b/test/prism/ractor_test.rb
new file mode 100644
index 0000000000..0e008ffb08
--- /dev/null
+++ b/test/prism/ractor_test.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+return unless defined?(Ractor) && Process.respond_to?(:fork)
+
+require_relative "test_helper"
+
+module Prism
+ class RactorTest < TestCase
+ def test_version
+ assert_match(/\A\d+\.\d+\.\d+\z/, with_ractor { Prism::VERSION })
+ end
+
+ def test_parse_file
+ assert_equal("Prism::ParseResult", with_ractor(__FILE__) { |filepath| Prism.parse_file(filepath).class })
+ end
+
+ def test_lex_file
+ assert_equal("Prism::LexResult", with_ractor(__FILE__) { |filepath| Prism.lex_file(filepath).class })
+ end
+
+ def test_parse_file_comments
+ assert_equal("Array", with_ractor(__FILE__) { |filepath| Prism.parse_file_comments(filepath).class })
+ end
+
+ def test_parse_lex_file
+ assert_equal("Prism::ParseLexResult", with_ractor(__FILE__) { |filepath| Prism.parse_lex_file(filepath).class })
+ end
+
+ def test_parse_success
+ assert_equal("true", with_ractor("1 + 1") { |source| Prism.parse_success?(source) })
+ end
+
+ def test_parse_failure
+ assert_equal("true", with_ractor("1 +") { |source| Prism.parse_failure?(source) })
+ end
+
+ def test_string_query_local
+ assert_equal("true", with_ractor("foo") { |source| StringQuery.local?(source) })
+ end
+
+ def test_string_query_constant
+ assert_equal("true", with_ractor("FOO") { |source| StringQuery.constant?(source) })
+ end
+
+ def test_string_query_method_name
+ assert_equal("true", with_ractor("foo?") { |source| StringQuery.method_name?(source) })
+ end
+
+ if !ENV["PRISM_BUILD_MINIMAL"]
+ def test_dump_file
+ result = with_ractor(__FILE__) { |filepath| Prism.dump_file(filepath) }
+ assert_operator(result, :start_with?, "PRISM")
+ end
+ end
+
+ private
+
+ # Note that this must be done in a subprocess, otherwise it can mess up
+ # CRuby's test suite.
+ def with_ractor(*arguments, &block)
+ IO.popen("-") do |reader|
+ if reader
+ reader.gets.chomp
+ else
+ ractor = ignore_warnings { Ractor.new(*arguments, &block) }
+
+ # Somewhere in the Ruby 4.0.* series, Ractor#take was removed and
+ # Ractor#value was added.
+ puts(ractor.respond_to?(:value) ? ractor.value : ractor.take)
+ end
+ end
+ end
+ end
+end
diff --git a/test/prism/regexp_test.rb b/test/prism/regexp_test.rb
new file mode 100644
index 0000000000..cde0c23f97
--- /dev/null
+++ b/test/prism/regexp_test.rb
@@ -0,0 +1,265 @@
+# frozen_string_literal: true
+
+require_relative "test_helper"
+
+module Prism
+ class RegexpTest < TestCase
+ ############################################################################
+ # These tests test the actual use case of extracting named capture groups
+ ############################################################################
+
+ def test_named_captures_with_arrows
+ assert_equal([:foo], named_captures("(?<foo>bar)"))
+ end
+
+ def test_named_captures_with_single_quotes
+ assert_equal([:foo], named_captures("(?'foo'bar)"))
+ end
+
+ def test_nested_named_captures_with_arrows
+ assert_equal([:foo, :bar], named_captures("(?<foo>(?<bar>baz))"))
+ end
+
+ def test_nested_named_captures_with_single_quotes
+ assert_equal([:foo, :bar], named_captures("(?'foo'(?'bar'baz))"))
+ end
+
+ def test_allows_duplicate_named_captures
+ assert_equal([:foo], named_captures("(?<foo>bar)(?<foo>baz)"))
+ end
+
+ def test_named_capture_inside_fake_range_quantifier
+ assert_equal([:foo], named_captures("foo{1, (?<foo>2)}"))
+ end
+
+ def test_fake_named_captures_inside_character_sets
+ assert_equal([], named_captures("[a-z(?<foo>)]"))
+ end
+
+ def test_fake_named_capture_inside_character_set_with_escaped_ending
+ assert_equal([], named_captures("[a-z\\](?<foo>)]"))
+ end
+
+ ############################################################################
+ # These tests test the rest of the AST. They are not exhaustive, but they
+ # should cover the most common cases. We test these to make sure we don't
+ # accidentally regress and stop being able to extract named captures.
+ ############################################################################
+
+ def test_alternation
+ assert_valid_regexp("foo|bar")
+ end
+
+ def test_anchors
+ assert_valid_regexp("^foo$")
+ end
+
+ def test_any
+ assert_valid_regexp(".")
+ end
+
+ def test_posix_character_classes
+ assert_valid_regexp("[[:digit:]]")
+ end
+
+ def test_negated_posix_character_classes
+ assert_valid_regexp("[[:^digit:]]")
+ end
+
+ def test_invalid_posix_character_classes_should_fall_back_to_regular_classes
+ assert_valid_regexp("[[:foo]]")
+ end
+
+ def test_character_sets
+ assert_valid_regexp("[abc]")
+ end
+
+ def test_nested_character_sets
+ assert_valid_regexp("[[abc]]")
+ end
+
+ def test_nested_character_sets_with_operators
+ assert_valid_regexp("[[abc] && [def]]")
+ end
+
+ def test_named_capture_inside_nested_character_set
+ assert_equal([], named_captures("[foo (?<foo>bar)]"))
+ end
+
+ def test_negated_character_sets
+ assert_valid_regexp("[^abc]")
+ end
+
+ def test_character_ranges
+ assert_valid_regexp("[a-z]")
+ end
+
+ def test_negated_character_ranges
+ assert_valid_regexp("[^a-z]")
+ end
+
+ def test_comments
+ assert_valid_regexp("(?#foo)")
+ end
+
+ def test_comments_with_escaped_parentheses
+ assert_valid_regexp("(?#foo\\)\\))")
+ end
+
+ def test_non_capturing_groups
+ assert_valid_regexp("(?:foo)")
+ end
+
+ def test_positive_lookaheads
+ assert_valid_regexp("(?=foo)")
+ end
+
+ def test_negative_lookaheads
+ assert_valid_regexp("(?!foo)")
+ end
+
+ def test_positive_lookbehinds
+ assert_valid_regexp("(?<=foo)")
+ end
+
+ def test_negative_lookbehinds
+ assert_valid_regexp("(?<!foo)")
+ end
+
+ def test_atomic_groups
+ assert_valid_regexp("(?>foo)")
+ end
+
+ def test_absence_operator
+ assert_valid_regexp("(?~foo)")
+ end
+
+ def test_conditional_expression_with_index
+ assert_valid_regexp("(?(1)foo)")
+ end
+
+ def test_conditional_expression_with_name
+ assert_valid_regexp("(?(foo)bar)")
+ end
+
+ def test_conditional_expression_with_group
+ assert_valid_regexp("(?(<foo>)bar)")
+ end
+
+ def test_options_on_groups
+ assert_valid_regexp("(?imxdau:foo)")
+ end
+
+ def test_options_on_groups_getting_turned_off
+ assert_valid_regexp("(?-imx:foo)")
+ end
+
+ def test_options_on_groups_some_getting_turned_on_some_getting_turned_off
+ assert_valid_regexp("(?im-x:foo)")
+ end
+
+ def test_star_quantifier
+ assert_valid_regexp("foo*")
+ end
+
+ def test_plus_quantifier
+ assert_valid_regexp("foo+")
+ end
+
+ def test_question_mark_quantifier
+ assert_valid_regexp("foo?")
+ end
+
+ def test_endless_range_quantifier
+ assert_valid_regexp("foo{1,}")
+ end
+
+ def test_beginless_range_quantifier
+ assert_valid_regexp("foo{,1}")
+ end
+
+ def test_range_quantifier
+ assert_valid_regexp("foo{1,2}")
+ end
+
+ def test_fake_range_quantifier_because_of_spaces
+ assert_valid_regexp("foo{1, 2}")
+ end
+
+ def test_fake_range_quantifier_because_unclosed
+ assert_valid_regexp("\\A{")
+ end
+
+ ############################################################################
+ # These test that flag values are correct.
+ ############################################################################
+
+ def test_flag_ignorecase
+ assert_equal(Regexp::IGNORECASE, options("i"))
+ end
+
+ def test_flag_extended
+ assert_equal(Regexp::EXTENDED, options("x"))
+ end
+
+ def test_flag_multiline
+ assert_equal(Regexp::MULTILINE, options("m"))
+ end
+
+ def test_flag_fixedencoding
+ assert_equal(Regexp::FIXEDENCODING, options("e"))
+ assert_equal(Regexp::FIXEDENCODING, options("u"))
+ assert_equal(Regexp::FIXEDENCODING, options("s"))
+ end
+
+ def test_flag_noencoding
+ assert_equal(Regexp::NOENCODING, options("n"))
+ end
+
+ def test_flag_once
+ assert_equal(0, options("o"))
+ end
+
+ def test_flag_combined
+ value = Regexp::IGNORECASE | Regexp::MULTILINE | Regexp::EXTENDED
+ assert_equal(value, options("mix"))
+ end
+
+ def test_last_encoding_option_wins
+ regex = "/foo/nu"
+ option = Prism.parse_statement(regex).options
+
+ assert_equal Regexp::FIXEDENCODING, option
+
+ regex = "/foo/un"
+ option = Prism.parse_statement(regex).options
+
+ assert_equal Regexp::NOENCODING, option
+ end
+
+ private
+
+ def assert_valid_regexp(source)
+ assert Prism.parse_success?("/#{source}/ =~ \"\"")
+ end
+
+ def named_captures(source)
+ Prism.parse("/#{source}/ =~ \"\"").value.locals
+ end
+
+ def options(flags)
+ options =
+ ["/foo/#{flags}", "/foo\#{1}/#{flags}"].map do |source|
+ Prism.parse_statement(source).options
+ end
+
+ # Check that we get the same set of options from both regular expressions
+ # and interpolated regular expressions.
+ assert_equal(1, options.uniq.length)
+
+ # Return the options from the first regular expression since we know they
+ # are the same.
+ options.first
+ end
+ end
+end
diff --git a/test/prism/result/attribute_write_test.rb b/test/prism/result/attribute_write_test.rb
new file mode 100644
index 0000000000..8f2e352738
--- /dev/null
+++ b/test/prism/result/attribute_write_test.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class AttributeWriteTest < TestCase
+ module Target
+ def self.value
+ 2
+ end
+
+ def self.value=(value)
+ 2
+ end
+
+ def self.[]=(index, value)
+ 2
+ end
+ end
+
+ def test_named_call_with_operator
+ assert_attribute_write("Target.value = 1")
+ end
+
+ def test_named_call_without_operator
+ assert_attribute_write("Target.value=(1)")
+ end
+
+ def test_indexed_call_with_operator
+ assert_attribute_write("Target[0] = 1")
+ end
+
+ def test_indexed_call_without_operator
+ refute_attribute_write("Target.[]=(0, 1)")
+ end
+
+ def test_comparison_operators
+ refute_attribute_write("Target.value == 1")
+ refute_attribute_write("Target.value === 1")
+ end
+
+ private
+
+ def assert_attribute_write(source)
+ call = Prism.parse_statement(source)
+ assert(call.attribute_write?)
+ assert_equal(1, eval(source))
+ end
+
+ def refute_attribute_write(source)
+ call = Prism.parse_statement(source)
+ refute(call.attribute_write?)
+ refute_equal(1, eval(source))
+ end
+ end
+end
diff --git a/test/prism/result/breadth_first_search_test.rb b/test/prism/result/breadth_first_search_test.rb
new file mode 100644
index 0000000000..7e7962f172
--- /dev/null
+++ b/test/prism/result/breadth_first_search_test.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class BreadthFirstSearchTest < TestCase
+ def test_breadth_first_search
+ result = Prism.parse("[1 + 2, 2]")
+ found =
+ result.value.breadth_first_search do |node|
+ node.is_a?(IntegerNode) && node.value == 2
+ end
+
+ refute_nil found
+ assert_equal 8, found.start_offset
+ end
+
+ def test_breadth_first_search_all
+ result = Prism.parse("[1 + 2, 2]")
+ found_nodes =
+ result.value.breadth_first_search_all do |node|
+ node.is_a?(IntegerNode)
+ end
+
+ assert_equal 3, found_nodes.size
+ assert_equal 8, found_nodes[0].start_offset
+ end
+ end
+end
diff --git a/test/prism/result/comments_test.rb b/test/prism/result/comments_test.rb
new file mode 100644
index 0000000000..178623a75f
--- /dev/null
+++ b/test/prism/result/comments_test.rb
@@ -0,0 +1,138 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class CommentsTest < TestCase
+ def test_comment_inline
+ source = "# comment"
+ assert_equal [0], Prism.parse(source).source.offsets
+
+ assert_comment(
+ source,
+ InlineComment,
+ start_offset: 0,
+ end_offset: 9,
+ start_line: 1,
+ end_line: 1,
+ start_column: 0,
+ end_column: 9
+ )
+ end
+
+ def test_comment_inline_def
+ source = <<~RUBY
+ def foo
+ # a comment
+ end
+ RUBY
+
+ assert_comment(
+ source,
+ InlineComment,
+ start_offset: 10,
+ end_offset: 21,
+ start_line: 2,
+ end_line: 2,
+ start_column: 2,
+ end_column: 13
+ )
+ end
+
+ def test___END__
+ result = Prism.parse(<<~RUBY)
+ __END__
+ comment
+ RUBY
+
+ data_loc = result.data_loc
+ assert_equal 0, data_loc.start_offset
+ assert_equal 16, data_loc.end_offset
+ end
+
+ def test___END__crlf
+ result = Prism.parse("__END__\r\ncomment\r\n")
+
+ data_loc = result.data_loc
+ assert_equal 0, data_loc.start_offset
+ assert_equal 18, data_loc.end_offset
+ end
+
+ def test_comment_embedded_document
+ source = <<~RUBY
+ =begin
+ comment
+ =end
+ RUBY
+
+ assert_comment(
+ source,
+ EmbDocComment,
+ start_offset: 0,
+ end_offset: 20,
+ start_line: 1,
+ end_line: 4,
+ start_column: 0,
+ end_column: 0
+ )
+ end
+
+ def test_comment_embedded_document_with_content_on_same_line
+ source = <<~RUBY
+ =begin other stuff
+ =end
+ RUBY
+
+ assert_comment(
+ source,
+ EmbDocComment,
+ start_offset: 0,
+ end_offset: 24,
+ start_line: 1,
+ end_line: 3,
+ start_column: 0,
+ end_column: 0
+ )
+ end
+
+ def test_attaching_comments
+ source = <<~RUBY
+ # Foo class
+ class Foo
+ # bar method
+ def bar
+ # baz invocation
+ baz
+ end # bar end
+ end # Foo end
+ RUBY
+
+ result = Prism.parse(source)
+ result.attach_comments!
+ tree = result.value
+ class_node = tree.statements.body.first
+ method_node = class_node.body.body.first
+ call_node = method_node.body.body.first
+
+ assert_equal("# Foo class\n# Foo end", class_node.location.comments.map { |c| c.location.slice }.join("\n"))
+ assert_equal("# bar method\n# bar end", method_node.location.comments.map { |c| c.location.slice }.join("\n"))
+ assert_equal("# baz invocation", call_node.location.comments.map { |c| c.location.slice }.join("\n"))
+ end
+
+ private
+
+ def assert_comment(source, type, start_offset:, end_offset:, start_line:, end_line:, start_column:, end_column:)
+ result = Prism.parse(source)
+ assert result.errors.empty?, result.errors.map(&:message).join("\n")
+ assert_kind_of type, result.comments.first
+
+ location = result.comments.first.location
+ assert_equal start_offset, location.start_offset, -> { "Expected start_offset to be #{start_offset}" }
+ assert_equal end_offset, location.end_offset, -> { "Expected end_offset to be #{end_offset}" }
+ assert_equal start_line, location.start_line, -> { "Expected start_line to be #{start_line}" }
+ assert_equal end_line, location.end_line, -> { "Expected end_line to be #{end_line}" }
+ assert_equal start_column, location.start_column, -> { "Expected start_column to be #{start_column}" }
+ assert_equal end_column, location.end_column, -> { "Expected end_column to be #{end_column}" }
+ end
+ end
+end
diff --git a/test/prism/result/constant_path_node_test.rb b/test/prism/result/constant_path_node_test.rb
new file mode 100644
index 0000000000..75925600ca
--- /dev/null
+++ b/test/prism/result/constant_path_node_test.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ConstantPathNodeTest < TestCase
+ def test_full_name_for_constant_path
+ source = <<~RUBY
+ Foo:: # comment
+ Bar::Baz::
+ Qux
+ RUBY
+
+ constant_path = Prism.parse_statement(source)
+ assert_equal("Foo::Bar::Baz::Qux", constant_path.full_name)
+ end
+
+ def test_full_name_for_constant_path_with_self
+ source = <<~RUBY
+ self:: # comment
+ Bar::Baz::
+ Qux
+ RUBY
+
+ constant_path = Prism.parse_statement(source)
+ assert_raise(ConstantPathNode::DynamicPartsInConstantPathError) do
+ constant_path.full_name
+ end
+ end
+
+ def test_full_name_for_constant_path_with_variable
+ source = <<~RUBY
+ foo:: # comment
+ Bar::Baz::
+ Qux
+ RUBY
+
+ constant_path = Prism.parse_statement(source)
+
+ assert_raise(ConstantPathNode::DynamicPartsInConstantPathError) do
+ constant_path.full_name
+ end
+ end
+
+ def test_full_name_for_constant_path_target
+ source = <<~RUBY
+ Foo:: # comment
+ Bar::Baz::
+ Qux, Something = [1, 2]
+ RUBY
+
+ node = Prism.parse_statement(source)
+ assert_equal("Foo::Bar::Baz::Qux", node.lefts.first.full_name)
+ end
+
+ def test_full_name_for_constant_path_with_stovetop_start
+ source = <<~RUBY
+ ::Foo:: # comment
+ Bar::Baz::
+ Qux, Something = [1, 2]
+ RUBY
+
+ node = Prism.parse_statement(source)
+ assert_equal("::Foo::Bar::Baz::Qux", node.lefts.first.full_name)
+ end
+
+ def test_full_name_for_constant_path_target_with_non_constant_parent
+ source = <<~RUBY
+ self::Foo, Bar = [1, 2]
+ RUBY
+
+ constant_target = Prism.parse_statement(source)
+ dynamic, static = constant_target.lefts
+
+ assert_raise(ConstantPathNode::DynamicPartsInConstantPathError) do
+ dynamic.full_name
+ end
+
+ assert_equal("Bar", static.full_name)
+ end
+
+ def test_full_name_for_constant_read_node
+ source = <<~RUBY
+ Bar
+ RUBY
+
+ constant = Prism.parse_statement(source)
+ assert_equal("Bar", constant.full_name)
+ end
+ end
+end
diff --git a/test/prism/result/continuable_test.rb b/test/prism/result/continuable_test.rb
new file mode 100644
index 0000000000..3533552167
--- /dev/null
+++ b/test/prism/result/continuable_test.rb
@@ -0,0 +1,124 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ContinuableTest < TestCase
+ def test_valid_input
+ # Valid input is not continuable (nothing to continue).
+ refute_predicate Prism.parse("1 + 1"), :continuable?
+ refute_predicate Prism.parse(""), :continuable?
+ end
+
+ def test_stray_closing_tokens
+ # Stray closing tokens make input non-continuable regardless of what
+ # follows (matches the feature-request examples exactly).
+ refute_predicate Prism.parse("1 + ]"), :continuable?
+ refute_predicate Prism.parse("end.tap do"), :continuable?
+
+ # A mix: stray end plus an unclosed block is not continuable because the
+ # stray end cannot be fixed by appending more input.
+ refute_predicate Prism.parse("end\ntap do"), :continuable?
+ end
+
+ def test_unclosed_constructs
+ # Unclosed constructs are continuable.
+ assert_predicate Prism.parse("1 + ["), :continuable?
+ assert_predicate Prism.parse("tap do"), :continuable?
+ end
+
+ def test_unclosed_keywords
+ assert_predicate Prism.parse("def foo"), :continuable?
+ assert_predicate Prism.parse("class Foo"), :continuable?
+ assert_predicate Prism.parse("module Foo"), :continuable?
+ assert_predicate Prism.parse("if true"), :continuable?
+ assert_predicate Prism.parse("while true"), :continuable?
+ assert_predicate Prism.parse("begin"), :continuable?
+ assert_predicate Prism.parse("for x in [1]"), :continuable?
+ end
+
+ def test_unclosed_delimiters
+ assert_predicate Prism.parse("{"), :continuable?
+ assert_predicate Prism.parse("foo("), :continuable?
+ assert_predicate Prism.parse('"hello'), :continuable?
+ assert_predicate Prism.parse("'hello"), :continuable?
+ assert_predicate Prism.parse("<<~HEREDOC\nhello"), :continuable?
+ end
+
+ def test_trailing_whitespace
+ # Trailing whitespace or newlines should not affect continuability.
+ assert_predicate Prism.parse("class A\n"), :continuable?
+ assert_predicate Prism.parse("def f "), :continuable?
+ assert_predicate Prism.parse("def f\n"), :continuable?
+ assert_predicate Prism.parse("def f\n "), :continuable?
+ assert_predicate Prism.parse("( "), :continuable?
+ assert_predicate Prism.parse("(\n"), :continuable?
+ assert_predicate Prism.parse("1 +\n"), :continuable?
+ end
+
+ def test_incomplete_expressions
+ assert_predicate Prism.parse("-"), :continuable?
+ assert_predicate Prism.parse("[1,"), :continuable?
+ assert_predicate Prism.parse("f arg1,"), :continuable?
+ assert_predicate Prism.parse("def f ="), :continuable?
+ assert_predicate Prism.parse("def $a"), :continuable?
+ assert_predicate Prism.parse("a ="), :continuable?
+ assert_predicate Prism.parse("a,b"), :continuable?
+ end
+
+ def test_modifier_keywords
+ assert_predicate Prism.parse("return if"), :continuable?
+ assert_predicate Prism.parse("return unless"), :continuable?
+ assert_predicate Prism.parse("while"), :continuable?
+ assert_predicate Prism.parse("until"), :continuable?
+ end
+
+ def test_ternary_operator
+ assert_predicate Prism.parse("x ?"), :continuable?
+ assert_predicate Prism.parse("x ? y :"), :continuable?
+ end
+
+ def test_class_with_superclass
+ assert_predicate Prism.parse("class Foo <"), :continuable?
+ end
+
+ def test_keyword_expressions
+ assert_predicate Prism.parse("not"), :continuable?
+ assert_predicate Prism.parse("defined?"), :continuable?
+ assert_predicate Prism.parse("module"), :continuable?
+ end
+
+ def test_for_loops
+ assert_predicate Prism.parse("for"), :continuable?
+ assert_predicate Prism.parse("for x in"), :continuable?
+ end
+
+ def test_pattern_matching
+ assert_predicate Prism.parse("foo => ["), :continuable?
+ assert_predicate Prism.parse("case foo; when"), :continuable?
+ end
+
+ def test_splat_and_block_pass
+ assert_predicate Prism.parse("[*"), :continuable?
+ assert_predicate Prism.parse("f(**"), :continuable?
+ assert_predicate Prism.parse("f(&"), :continuable?
+ end
+
+ def test_default_parameter_value
+ assert_predicate Prism.parse("def f(x ="), :continuable?
+ end
+
+ def test_line_continuation
+ assert_predicate Prism.parse("1 +\\"), :continuable?
+ assert_predicate Prism.parse("\"foo\" \\"), :continuable?
+ end
+
+ def test_embedded_document
+ # Embedded document (=begin) truncated at various points.
+ assert_predicate Prism.parse("=b"), :continuable?
+ assert_predicate Prism.parse("=beg"), :continuable?
+ assert_predicate Prism.parse("=begin"), :continuable?
+ assert_predicate Prism.parse("foo\n=b"), :continuable?
+ end
+ end
+end
diff --git a/test/prism/result/equality_test.rb b/test/prism/result/equality_test.rb
new file mode 100644
index 0000000000..4f6e665a88
--- /dev/null
+++ b/test/prism/result/equality_test.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class EqualityTest < TestCase
+ def test_equality
+ assert_operator Prism.parse_statement("1"), :===, Prism.parse_statement("1")
+ assert_operator Prism.parse("1").value, :===, Prism.parse("1").value
+
+ complex_source = "class Something; @var = something.else { _1 }; end"
+ assert_operator Prism.parse_statement(complex_source), :===, Prism.parse_statement(complex_source)
+
+ refute_operator Prism.parse_statement("1"), :===, Prism.parse_statement("2")
+ refute_operator Prism.parse_statement("1"), :===, Prism.parse_statement("0x1")
+
+ complex_source_1 = "class Something; @var = something.else { _1 }; end"
+ complex_source_2 = "class Something; @var = something.else { _2 }; end"
+ refute_operator Prism.parse_statement(complex_source_1), :===, Prism.parse_statement(complex_source_2)
+ end
+ end
+end
diff --git a/test/prism/result/error_recovery_test.rb b/test/prism/result/error_recovery_test.rb
new file mode 100644
index 0000000000..d07c858d1b
--- /dev/null
+++ b/test/prism/result/error_recovery_test.rb
@@ -0,0 +1,237 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ErrorRecoveryTest < TestCase
+ def test_alias_global_variable_node_old_name_symbol
+ result = Prism.parse("alias $a b")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.old_name
+ assert_kind_of SymbolNode, node.old_name.unexpected
+ end
+
+ def test_alias_global_variable_node_old_name_missing
+ result = Prism.parse("alias $a 42")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.old_name
+ assert_nil node.old_name.unexpected
+ end
+
+ def test_alias_method_node_old_name_global_variable
+ result = Prism.parse("alias a $b")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.old_name
+ assert_kind_of GlobalVariableReadNode, node.old_name.unexpected
+ end
+
+ def test_alias_method_node_old_name_missing
+ result = Prism.parse("alias a 42")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.old_name
+ assert_nil node.old_name.unexpected
+ end
+
+ def test_class_node_constant_path_call
+ result = Prism.parse("class 0.X; end")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.constant_path
+ assert_kind_of CallNode, node.constant_path.unexpected
+ end
+
+ def test_for_node_index_back_reference
+ result = Prism.parse("for $& in a; end")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.index
+ assert_kind_of BackReferenceReadNode, node.index.unexpected
+ end
+
+ def test_for_node_index_numbered_reference
+ result = Prism.parse("for $1 in a; end")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.index
+ assert_kind_of NumberedReferenceReadNode, node.index.unexpected
+ end
+
+ def test_for_node_index_missing
+ result = Prism.parse("for in 1..10; end")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.index
+ assert_nil node.index.unexpected
+ end
+
+ def test_interpolated_string_node_parts_xstring
+ result = Prism.parse("<<~`FOO` \"bar\"\nls\nFOO\n")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert node.parts.any? { |part| part.is_a?(ErrorRecoveryNode) && part.unexpected.is_a?(XStringNode) }
+ end
+
+ def test_interpolated_string_node_parts_interpolated_xstring
+ result = Prism.parse("<<~`FOO` \"bar\"\n\#{ls}\nFOO\n")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert node.parts.any? { |part| part.is_a?(ErrorRecoveryNode) && part.unexpected.is_a?(InterpolatedXStringNode) }
+ end
+
+ def test_module_node_constant_path_def
+ result = Prism.parse("module def foo; end")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.constant_path
+ assert_kind_of DefNode, node.constant_path.unexpected
+ end
+
+ def test_module_node_constant_path_missing
+ result = Prism.parse("module Parent module end")
+ refute result.success?
+
+ node = result.value.statements.body.first.body.body.first
+ assert_kind_of ErrorRecoveryNode, node.constant_path
+ assert_nil node.constant_path.unexpected
+ end
+
+ def test_multi_target_node_lefts_back_reference
+ result = Prism.parse("a, (b, $&) = z")
+ refute result.success?
+
+ node = result.value.statements.body.first.lefts.last
+ assert node.lefts.any? { |left| left.is_a?(ErrorRecoveryNode) && left.unexpected.is_a?(BackReferenceReadNode) }
+ end
+
+ def test_multi_target_node_lefts_numbered_reference
+ result = Prism.parse("a, (b, $1) = z")
+ refute result.success?
+
+ node = result.value.statements.body.first.lefts.last
+ assert node.lefts.any? { |left| left.is_a?(ErrorRecoveryNode) && left.unexpected.is_a?(NumberedReferenceReadNode) }
+ end
+
+ def test_multi_target_node_rights_back_reference
+ result = Prism.parse("a, (*, $&) = z")
+ refute result.success?
+
+ node = result.value.statements.body.first.lefts.last
+ assert node.rights.any? { |right| right.is_a?(ErrorRecoveryNode) && right.unexpected.is_a?(BackReferenceReadNode) }
+ end
+
+ def test_multi_target_node_rights_numbered_reference
+ result = Prism.parse("a, (*, $1) = z")
+ refute result.success?
+
+ node = result.value.statements.body.first.lefts.last
+ assert node.rights.any? { |right| right.is_a?(ErrorRecoveryNode) && right.unexpected.is_a?(NumberedReferenceReadNode) }
+ end
+
+ def test_multi_write_node_lefts_back_reference
+ result = Prism.parse("$&, = z")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert node.lefts.any? { |left| left.is_a?(ErrorRecoveryNode) && left.unexpected.is_a?(BackReferenceReadNode) }
+ end
+
+ def test_multi_write_node_lefts_numbered_reference
+ result = Prism.parse("$1, = z")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert node.lefts.any? { |left| left.is_a?(ErrorRecoveryNode) && left.unexpected.is_a?(NumberedReferenceReadNode) }
+ end
+
+ def test_multi_write_node_rights_back_reference
+ result = Prism.parse("*, $& = z")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert node.rights.any? { |right| right.is_a?(ErrorRecoveryNode) && right.unexpected.is_a?(BackReferenceReadNode) }
+ end
+
+ def test_multi_write_node_rights_numbered_reference
+ result = Prism.parse("*, $1 = z")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert node.rights.any? { |right| right.is_a?(ErrorRecoveryNode) && right.unexpected.is_a?(NumberedReferenceReadNode) }
+ end
+
+ def test_parameters_node_posts_keyword_rest
+ result = Prism.parse("def f(**kwargs, ...); end")
+ refute result.success?
+
+ node = result.value.statements.body.first.parameters
+ assert node.posts.any? { |post| post.is_a?(ErrorRecoveryNode) && post.unexpected.is_a?(KeywordRestParameterNode) }
+ end
+
+ def test_parameters_node_posts_no_keywords
+ result = Prism.parse("def f(**nil, ...); end")
+ refute result.success?
+
+ node = result.value.statements.body.first.parameters
+ assert node.posts.any? { |post| post.is_a?(ErrorRecoveryNode) && post.unexpected.is_a?(NoKeywordsParameterNode) }
+ end
+
+ def test_parameters_node_posts_forwarding
+ result = Prism.parse("def f(..., ...); end")
+ refute result.success?
+
+ node = result.value.statements.body.first.parameters
+ assert node.posts.any? { |post| post.is_a?(ErrorRecoveryNode) && post.unexpected.is_a?(ForwardingParameterNode) }
+ end
+
+ def test_pinned_variable_node_variable_missing
+ result = Prism.parse("foo in ^Bar")
+ refute result.success?
+
+ node = result.value.statements.body.first.pattern
+ assert_kind_of ErrorRecoveryNode, node.variable
+ assert_nil node.variable.unexpected
+ end
+
+ def test_rescue_node_reference_back_reference
+ result = Prism.parse("begin; rescue => $&; end")
+ refute result.success?
+
+ node = result.value.statements.body.first.rescue_clause
+ assert_kind_of ErrorRecoveryNode, node.reference
+ assert_kind_of BackReferenceReadNode, node.reference.unexpected
+ end
+
+ def test_rescue_node_reference_numbered_reference
+ result = Prism.parse("begin; rescue => $1; end")
+ refute result.success?
+
+ node = result.value.statements.body.first.rescue_clause
+ assert_kind_of ErrorRecoveryNode, node.reference
+ assert_kind_of NumberedReferenceReadNode, node.reference.unexpected
+ end
+
+ def test_rescue_node_reference_missing
+ result = Prism.parse("begin; rescue =>; end")
+ refute result.success?
+
+ node = result.value.statements.body.first.rescue_clause
+ assert_kind_of ErrorRecoveryNode, node.reference
+ assert_nil node.reference.unexpected
+ end
+ end
+end
diff --git a/test/prism/result/heredoc_test.rb b/test/prism/result/heredoc_test.rb
new file mode 100644
index 0000000000..7913c04a88
--- /dev/null
+++ b/test/prism/result/heredoc_test.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class HeredocTest < TestCase
+ def test_heredoc?
+ refute Prism.parse_statement("\"foo\"").heredoc?
+ refute Prism.parse_statement("\"foo \#{1}\"").heredoc?
+ refute Prism.parse_statement("`foo`").heredoc?
+ refute Prism.parse_statement("`foo \#{1}`").heredoc?
+
+ assert Prism.parse_statement("<<~HERE\nfoo\nHERE\n").heredoc?
+ assert Prism.parse_statement("<<~HERE\nfoo \#{1}\nHERE\n").heredoc?
+ assert Prism.parse_statement("<<~`HERE`\nfoo\nHERE\n").heredoc?
+ assert Prism.parse_statement("<<~`HERE`\nfoo \#{1}\nHERE\n").heredoc?
+ end
+ end
+end
diff --git a/test/prism/result/implicit_array_test.rb b/test/prism/result/implicit_array_test.rb
new file mode 100644
index 0000000000..e7ddde70aa
--- /dev/null
+++ b/test/prism/result/implicit_array_test.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ImplicitArrayTest < TestCase
+ def test_call_node
+ assert_implicit_array("a.a = *b")
+ assert_implicit_array("a.a = 1, 2, 3")
+ assert_implicit_array("a[a] = *b")
+ assert_implicit_array("a[a] = 1, 2, 3")
+ end
+
+ def test_class_variable_write_node
+ assert_implicit_array("@@a = *b")
+ assert_implicit_array("@@a = 1, 2, 3")
+ end
+
+ def test_constant_path_write_node
+ assert_implicit_array("A::A = *b")
+ assert_implicit_array("A::A = 1, 2, 3")
+ end
+
+ def test_constant_write_node
+ assert_implicit_array("A = *b")
+ assert_implicit_array("A = 1, 2, 3")
+ end
+
+ def test_global_variable_write_node
+ assert_implicit_array("$a = *b")
+ assert_implicit_array("$a = 1, 2, 3")
+ end
+
+ def test_instance_variable_write_node
+ assert_implicit_array("@a = *b")
+ assert_implicit_array("@a = 1, 2, 3")
+ end
+
+ def test_local_variable_write_node
+ assert_implicit_array("a = *b")
+ assert_implicit_array("a = 1, 2, 3")
+ end
+
+ def test_multi_write_node
+ assert_implicit_array("a, b, c = *b")
+ assert_implicit_array("a, b, c = 1, 2, 3")
+ end
+
+ private
+
+ def assert_implicit_array(source)
+ assert Prism.parse_success?(source)
+ assert Prism.parse_failure?("if #{source} then end")
+
+ assert_valid_syntax(source)
+ refute_valid_syntax("if #{source} then end")
+ end
+ end
+end
diff --git a/test/prism/result/index_write_test.rb b/test/prism/result/index_write_test.rb
new file mode 100644
index 0000000000..0d5383b601
--- /dev/null
+++ b/test/prism/result/index_write_test.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class IndexWriteTest < TestCase
+ def test_keywords_3_3
+ assert_parse_success(<<~RUBY, "3.3.0")
+ foo[bar: 1] = 1
+ foo[bar: 1] &&= 1
+ foo[bar: 1] ||= 1
+ foo[bar: 1] += 1
+ RUBY
+
+ assert_parse_success(<<~RUBY, "3.3.0")
+ def foo(**)
+ bar[**] = 1
+ bar[**] &&= 1
+ bar[**] ||= 1
+ bar[**] += 1
+ end
+ RUBY
+ end
+
+ def test_block_3_3
+ assert_parse_success(<<~RUBY, "3.3.0")
+ foo[&bar] = 1
+ foo[&bar] &&= 1
+ foo[&bar] ||= 1
+ foo[&bar] += 1
+ RUBY
+
+ assert_parse_success(<<~RUBY, "3.3.0")
+ def foo(&)
+ bar[&] = 1
+ bar[&] &&= 1
+ bar[&] ||= 1
+ bar[&] += 1
+ end
+ RUBY
+ end
+
+ def test_keywords_latest
+ assert_parse_failure(<<~RUBY)
+ foo[bar: 1] = 1
+ foo[bar: 1] &&= 1
+ foo[bar: 1] ||= 1
+ foo[bar: 1] += 1
+ RUBY
+
+ assert_parse_failure(<<~RUBY)
+ def foo(**)
+ bar[**] = 1
+ bar[**] &&= 1
+ bar[**] ||= 1
+ bar[**] += 1
+ end
+ RUBY
+ end
+
+ def test_block_latest
+ assert_parse_failure(<<~RUBY)
+ foo[&bar] = 1
+ foo[&bar] &&= 1
+ foo[&bar] ||= 1
+ foo[&bar] += 1
+ RUBY
+
+ assert_parse_failure(<<~RUBY)
+ def foo(&)
+ bar[&] = 1
+ bar[&] &&= 1
+ bar[&] ||= 1
+ bar[&] += 1
+ end
+ RUBY
+ end
+
+ private
+
+ def assert_parse_success(source, version = "latest")
+ assert Prism.parse_success?(source, version: version)
+ end
+
+ def assert_parse_failure(source, version = "latest")
+ assert Prism.parse_failure?(source, version: version)
+ end
+ end
+end
diff --git a/test/prism/result/integer_base_flags_test.rb b/test/prism/result/integer_base_flags_test.rb
new file mode 100644
index 0000000000..e3ab8c6910
--- /dev/null
+++ b/test/prism/result/integer_base_flags_test.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class IntegerBaseFlagsTest < TestCase
+ # Through some bit hackery, we want to allow consumers to use the integer
+ # base flags as the base itself. It has a nice property that the current
+ # alignment provides them in the correct order. So here we test that our
+ # assumption holds so that it doesn't change out from under us.
+ #
+ # In C, this would look something like:
+ #
+ # ((flags & ~DECIMAL) >> 1) || 10
+ #
+ # We have to do some other work in Ruby because 0 is truthy and ~ on an
+ # integer doesn't have a fixed width.
+ def test_flags
+ assert_equal 2, base("0b1")
+ assert_equal 8, base("0o1")
+ assert_equal 10, base("0d1")
+ assert_equal 16, base("0x1")
+ end
+
+ private
+
+ def base(source)
+ node = Prism.parse_statement(source)
+ value = (node.send(:flags) & (0b111100 - IntegerBaseFlags::DECIMAL)) >> 1
+ value == 0 ? 10 : value
+ end
+ end
+end
diff --git a/test/prism/result/integer_parse_test.rb b/test/prism/result/integer_parse_test.rb
new file mode 100644
index 0000000000..7b5ce98bb6
--- /dev/null
+++ b/test/prism/result/integer_parse_test.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class IntegerParseTest < TestCase
+ def test_integer_parse
+ assert_integer_parse(1)
+ assert_integer_parse(50)
+ assert_integer_parse(100)
+ assert_integer_parse(100, "1_0_0")
+ assert_integer_parse(8, "0_1_0")
+
+ assert_integer_parse(10, "0b1010")
+ assert_integer_parse(10, "0B1010")
+ assert_integer_parse(10, "0o12")
+ assert_integer_parse(10, "0O12")
+ assert_integer_parse(10, "012")
+ assert_integer_parse(10, "0d10")
+ assert_integer_parse(10, "0D10")
+ assert_integer_parse(10, "0xA")
+ assert_integer_parse(10, "0XA")
+
+ assert_integer_parse(2**32)
+ assert_integer_parse(2**64 + 2**32)
+ assert_integer_parse(2**128 + 2**64 + 2**32)
+
+ num = 99 ** 99
+ assert_integer_parse(num, "0b#{num.to_s(2)}")
+ assert_integer_parse(num, "0o#{num.to_s(8)}")
+ assert_integer_parse(num, "0d#{num.to_s(10)}")
+ assert_integer_parse(num, "0x#{num.to_s(16)}")
+ end
+
+ private
+
+ def assert_integer_parse(expected, source = expected.to_s)
+ assert_equal expected, Prism.parse_statement(source).value
+ end
+ end
+end
diff --git a/test/prism/result/named_capture_test.rb b/test/prism/result/named_capture_test.rb
new file mode 100644
index 0000000000..36cb910899
--- /dev/null
+++ b/test/prism/result/named_capture_test.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class NamedCaptureTest < TestCase
+ def test_hex_escapes
+ assert_equal :😀, parse_name("\\xf0\\x9f\\x98\\x80")
+ end
+
+ def test_unicode_escape
+ assert_equal :し, parse_name("\\u3057")
+ end
+
+ def test_unicode_escapes_bracess
+ assert_equal :😀, parse_name("\\u{1f600}")
+ end
+
+ def test_octal_escapes
+ assert_equal :😀, parse_name("\\xf0\\x9f\\x98\\200")
+ end
+
+ private
+
+ def parse_name(content)
+ Prism.parse_statement("/(?<#{content}>)/ =~ ''").targets.first.name
+ end
+ end
+end
diff --git a/test/prism/result/node_id_test.rb b/test/prism/result/node_id_test.rb
new file mode 100644
index 0000000000..59b79bc574
--- /dev/null
+++ b/test/prism/result/node_id_test.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class NodeIdTest < TestCase
+ Fixture.each do |fixture|
+ define_method(fixture.test_name) { assert_node_ids(fixture.read) }
+ end
+
+ private
+
+ def assert_node_ids(source)
+ queue = [Prism.parse(source).value]
+ node_ids = []
+
+ while (node = queue.shift)
+ node_ids << node.node_id
+ queue.concat(node.compact_child_nodes)
+ end
+
+ node_ids.sort!
+ refute_includes node_ids, 0
+ assert_equal node_ids, node_ids.uniq
+ end
+ end
+end
diff --git a/test/prism/result/numeric_value_test.rb b/test/prism/result/numeric_value_test.rb
new file mode 100644
index 0000000000..0207fa6a86
--- /dev/null
+++ b/test/prism/result/numeric_value_test.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class NumericValueTest < TestCase
+ def test_numeric_value
+ assert_equal 123, Prism.parse_statement("123").value
+ assert_equal 123, Prism.parse_statement("1_23").value
+ assert_equal 3.14, Prism.parse_statement("3.14").value
+ assert_equal 3.14, Prism.parse_statement("3.1_4").value
+ assert_equal 42i, Prism.parse_statement("42i").value
+ assert_equal 42i, Prism.parse_statement("4_2i").value
+ assert_equal 42.1ri, Prism.parse_statement("42.1ri").value
+ assert_equal 42.1ri, Prism.parse_statement("42.1_0ri").value
+ assert_equal 3.14i, Prism.parse_statement("3.14i").value
+ assert_equal 3.14i, Prism.parse_statement("3.1_4i").value
+ assert_equal 42r, Prism.parse_statement("42r").value
+ assert_equal 42r, Prism.parse_statement("4_2r").value
+ assert_equal 0.5r, Prism.parse_statement("0.5r").value
+ assert_equal 0.5r, Prism.parse_statement("0.5_0r").value
+ assert_equal 42ri, Prism.parse_statement("42ri").value
+ assert_equal 42ri, Prism.parse_statement("4_2ri").value
+ assert_equal 0.5ri, Prism.parse_statement("0.5ri").value
+ assert_equal 0.5ri, Prism.parse_statement("0.5_0ri").value
+ assert_equal 0xFFr, Prism.parse_statement("0xFFr").value
+ assert_equal 0xFFr, Prism.parse_statement("0xF_Fr").value
+ assert_equal 0xFFri, Prism.parse_statement("0xFFri").value
+ assert_equal 0xFFri, Prism.parse_statement("0xF_Fri").value
+ end
+ end
+end
diff --git a/test/prism/result/overlap_test.rb b/test/prism/result/overlap_test.rb
new file mode 100644
index 0000000000..d605eeca44
--- /dev/null
+++ b/test/prism/result/overlap_test.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class OverlapTest < TestCase
+ Fixture.each do |fixture|
+ define_method(fixture.test_name) { assert_overlap(fixture) }
+ end
+
+ private
+
+ # Check that the location ranges of each node in the tree are a superset of
+ # their respective child nodes.
+ def assert_overlap(fixture)
+ queue = [Prism.parse_file(fixture.full_path).value]
+
+ while (current = queue.shift)
+ # We only want to compare parent/child location overlap in the case that
+ # we are not looking at a heredoc. That's because heredoc locations are
+ # special in that they only use the declaration of the heredoc.
+ compare = !(current.is_a?(StringNode) ||
+ current.is_a?(XStringNode) ||
+ current.is_a?(InterpolatedStringNode) ||
+ current.is_a?(InterpolatedXStringNode)) ||
+ !current.opening&.start_with?("<<")
+
+ current.child_nodes.each do |child|
+ # child_nodes can return nil values, so we need to skip those.
+ next unless child
+
+ # Now that we know we have a child node, add that to the queue.
+ queue << child
+
+ if compare
+ assert_operator current.location.start_offset, :<=, child.location.start_offset, -> {
+ "[#{fixture.full_path}] Parent node #{current.class} at #{current.location} does not start before child node #{child.class} at #{child.location}"
+ }
+
+ assert_operator current.location.end_offset, :>=, child.location.end_offset, -> {
+ "[#{fixture.full_path}] Parent node #{current.class} at #{current.location} does not end after child node #{child.class} at #{child.location}"
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/test/prism/result/regular_expression_options_test.rb b/test/prism/result/regular_expression_options_test.rb
new file mode 100644
index 0000000000..ff6e20526f
--- /dev/null
+++ b/test/prism/result/regular_expression_options_test.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class RegularExpressionOptionsTest < TestCase
+ def test_options
+ assert_equal "", Prism.parse_statement("__FILE__").filepath
+ assert_equal "foo.rb", Prism.parse_statement("__FILE__", filepath: "foo.rb").filepath
+
+ assert_equal 1, Prism.parse_statement("foo").location.start_line
+ assert_equal 10, Prism.parse_statement("foo", line: 10).location.start_line
+
+ refute Prism.parse_statement("\"foo\"").frozen?
+ assert Prism.parse_statement("\"foo\"", frozen_string_literal: true).frozen?
+ refute Prism.parse_statement("\"foo\"", frozen_string_literal: false).frozen?
+
+ assert_kind_of CallNode, Prism.parse_statement("foo")
+ assert_kind_of LocalVariableReadNode, Prism.parse_statement("foo", scopes: [[:foo]])
+ assert_equal 1, Prism.parse_statement("foo", scopes: [[:foo], []]).depth
+
+ assert_equal [:foo], Prism.parse("foo", scopes: [[:foo]]).value.locals
+ end
+ end
+end
diff --git a/test/prism/result/source_location_test.rb b/test/prism/result/source_location_test.rb
new file mode 100644
index 0000000000..a8d27b95a8
--- /dev/null
+++ b/test/prism/result/source_location_test.rb
@@ -0,0 +1,954 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class SourceLocationTest < TestCase
+ def test_AliasGlobalVariableNode
+ assert_location(AliasGlobalVariableNode, "alias $foo $bar")
+ end
+
+ def test_AliasMethodNode
+ assert_location(AliasMethodNode, "alias foo bar")
+ end
+
+ def test_AlternationPatternNode
+ assert_location(AlternationPatternNode, "foo => 0 | 1", 7...12, &:pattern)
+ end
+
+ def test_AndNode
+ assert_location(AndNode, "foo and bar")
+ assert_location(AndNode, "foo && bar")
+ end
+
+ def test_ArgumentsNode
+ assert_location(ArgumentsNode, "foo(bar, baz, qux)", 4...17, &:arguments)
+ end
+
+ def test_ArrayNode
+ assert_location(ArrayNode, "[foo, bar, baz]")
+ assert_location(ArrayNode, "%i[foo bar baz]")
+ assert_location(ArrayNode, "%I[foo bar baz]")
+ assert_location(ArrayNode, "%w[foo bar baz]")
+ assert_location(ArrayNode, "%W[foo bar baz]")
+ end
+
+ def test_ArrayPatternNode
+ assert_location(ArrayPatternNode, "foo => bar, baz", 7...15, &:pattern)
+ assert_location(ArrayPatternNode, "foo => [bar, baz]", 7...17, &:pattern)
+ assert_location(ArrayPatternNode, "foo => *bar", 7...11, &:pattern)
+ assert_location(ArrayPatternNode, "foo => []", 7...9, &:pattern)
+ assert_location(ArrayPatternNode, "foo => Foo[]", 7...12, &:pattern)
+ assert_location(ArrayPatternNode, "foo => Foo[bar]", 7...15, &:pattern)
+ end
+
+ def test_AssocNode
+ assert_location(AssocNode, "{ '': 1 }", 2...7) { |node| node.elements.first }
+ assert_location(AssocNode, "{ foo: :bar }", 2...11) { |node| node.elements.first }
+ assert_location(AssocNode, "{ :foo => :bar }", 2...14) { |node| node.elements.first }
+ assert_location(AssocNode, "foo(bar: :baz)", 4...13) { |node| node.arguments.arguments.first.elements.first }
+ end
+
+ def test_AssocSplatNode
+ assert_location(AssocSplatNode, "{ **foo }", 2...7) { |node| node.elements.first }
+ assert_location(AssocSplatNode, "foo(**bar)", 4...9) { |node| node.arguments.arguments.first.elements.first }
+ end
+
+ def test_BackReferenceReadNode
+ assert_location(BackReferenceReadNode, "$+")
+ end
+
+ def test_BeginNode
+ assert_location(BeginNode, "begin foo end")
+ assert_location(BeginNode, "begin foo rescue bar end")
+ assert_location(BeginNode, "begin foo; rescue bar\nelse baz end")
+ assert_location(BeginNode, "begin foo; rescue bar\nelse baz\nensure qux end")
+
+ assert_location(BeginNode, "class Foo\nrescue then end", 0..25, &:body)
+ assert_location(BeginNode, "module Foo\nrescue then end", 0..26, &:body)
+ end
+
+ def test_BlockArgumentNode
+ assert_location(BlockArgumentNode, "foo(&bar)", 4...8, &:block)
+ end
+
+ def test_BlockLocalVariableNode
+ assert_location(BlockLocalVariableNode, "foo { |;bar| }", 8...11) do |node|
+ node.block.parameters.locals.first
+ end
+ end
+
+ def test_BlockNode
+ assert_location(BlockNode, "foo {}", 4...6, &:block)
+ assert_location(BlockNode, "foo do end", 4...10, &:block)
+ end
+
+ def test_BlockParameterNode
+ assert_location(BlockParameterNode, "def foo(&bar) end", 8...12) { |node| node.parameters.block }
+ end
+
+ def test_BlockParametersNode
+ assert_location(BlockParametersNode, "foo { || }", 6...8) { |node| node.block.parameters }
+ assert_location(BlockParametersNode, "foo { |bar| baz }", 6...11) { |node| node.block.parameters }
+ assert_location(BlockParametersNode, "foo { |bar; baz| baz }", 6...16) { |node| node.block.parameters }
+
+ assert_location(BlockParametersNode, "-> () {}", 3...5, &:parameters)
+ assert_location(BlockParametersNode, "-> (bar) { baz }", 3...8, &:parameters)
+ assert_location(BlockParametersNode, "-> (bar; baz) { baz }", 3...13, &:parameters)
+ end
+
+ def test_BreakNode
+ assert_location(BreakNode, "tap { break }", 6...11) { |node| node.block.body.body.first }
+ assert_location(BreakNode, "tap { break foo }", 6...15) { |node| node.block.body.body.first }
+ assert_location(BreakNode, "tap { break foo, bar }", 6...20) { |node| node.block.body.body.first }
+ assert_location(BreakNode, "tap { break(foo) }", 6...16) { |node| node.block.body.body.first }
+ end
+
+ def test_CallNode
+ assert_location(CallNode, "foo")
+ assert_location(CallNode, "foo?")
+ assert_location(CallNode, "foo!")
+
+ assert_location(CallNode, "foo()")
+ assert_location(CallNode, "foo?()")
+ assert_location(CallNode, "foo!()")
+
+ assert_location(CallNode, "foo(bar)")
+ assert_location(CallNode, "foo?(bar)")
+ assert_location(CallNode, "foo!(bar)")
+
+ assert_location(CallNode, "!foo")
+ assert_location(CallNode, "~foo")
+ assert_location(CallNode, "+foo")
+ assert_location(CallNode, "-foo")
+
+ assert_location(CallNode, "not foo")
+ assert_location(CallNode, "not(foo)")
+ assert_location(CallNode, "not()")
+
+ assert_location(CallNode, "foo + bar")
+ assert_location(CallNode, "foo -\n bar")
+
+ assert_location(CallNode, "Foo()")
+ assert_location(CallNode, "Foo(bar)")
+
+ assert_location(CallNode, "Foo::Bar()")
+ assert_location(CallNode, "Foo::Bar(baz)")
+
+ assert_location(CallNode, "Foo::bar")
+ assert_location(CallNode, "Foo::bar()")
+ assert_location(CallNode, "Foo::bar(baz)")
+
+ assert_location(CallNode, "Foo.bar")
+ assert_location(CallNode, "Foo.bar()")
+ assert_location(CallNode, "Foo.bar(baz)")
+
+ assert_location(CallNode, "foo::bar")
+ assert_location(CallNode, "foo::bar()")
+ assert_location(CallNode, "foo::bar(baz)")
+
+ assert_location(CallNode, "foo.bar")
+ assert_location(CallNode, "foo.bar()")
+ assert_location(CallNode, "foo.bar(baz)")
+
+ assert_location(CallNode, "foo&.bar")
+ assert_location(CallNode, "foo&.bar()")
+ assert_location(CallNode, "foo&.bar(baz)")
+
+ assert_location(CallNode, "foo[]")
+ assert_location(CallNode, "foo[bar]")
+ assert_location(CallNode, "foo[bar, baz]")
+
+ assert_location(CallNode, "foo[] = 1")
+ assert_location(CallNode, "foo[bar] = 1")
+ assert_location(CallNode, "foo[bar, baz] = 1")
+
+ assert_location(CallNode, "foo.()")
+ assert_location(CallNode, "foo.(bar)")
+
+ assert_location(CallNode, "foo&.()")
+ assert_location(CallNode, "foo&.(bar)")
+
+ assert_location(CallNode, "foo::()")
+ assert_location(CallNode, "foo::(bar)")
+ assert_location(CallNode, "foo::(bar, baz)")
+
+ assert_location(CallNode, "foo bar baz")
+ assert_location(CallNode, "foo bar('baz')")
+ end
+
+ def test_CallAndWriteNode
+ assert_location(CallAndWriteNode, "foo.foo &&= bar")
+ end
+
+ def test_CallOperatorWriteNode
+ assert_location(CallOperatorWriteNode, "foo.foo += bar")
+ end
+
+ def test_CallOrWriteNode
+ assert_location(CallOrWriteNode, "foo.foo ||= bar")
+ end
+
+ def test_CallTargetNode
+ assert_location(CallTargetNode, "foo.bar, = baz", 0...7) do |node|
+ node.lefts.first
+ end
+ end
+
+ def test_CapturePatternNode
+ assert_location(CapturePatternNode, "case foo; in bar => baz; end", 13...23) do |node|
+ node.conditions.first.pattern
+ end
+ end
+
+ def test_CaseNode
+ assert_location(CaseNode, "case foo; when bar; end")
+ assert_location(CaseNode, "case foo; when bar; else; end")
+ assert_location(CaseNode, "case foo; when bar; when baz; end")
+ assert_location(CaseNode, "case foo; when bar; when baz; else; end")
+ end
+
+ def test_CaseMatchNode
+ assert_location(CaseMatchNode, "case foo; in bar; end")
+ assert_location(CaseMatchNode, "case foo; in bar; else; end")
+ assert_location(CaseMatchNode, "case foo; in bar; in baz; end")
+ assert_location(CaseMatchNode, "case foo; in bar; in baz; else; end")
+ end
+
+ def test_ClassNode
+ assert_location(ClassNode, "class Foo end")
+ assert_location(ClassNode, "class Foo < Bar; end")
+ end
+
+ def test_ClassVariableAndWriteNode
+ assert_location(ClassVariableAndWriteNode, "@@foo &&= bar")
+ end
+
+ def test_ClassVariableOperatorWriteNode
+ assert_location(ClassVariableOperatorWriteNode, "@@foo += bar")
+ end
+
+ def test_ClassVariableOrWriteNode
+ assert_location(ClassVariableOrWriteNode, "@@foo ||= bar")
+ end
+
+ def test_ClassVariableReadNode
+ assert_location(ClassVariableReadNode, "@@foo")
+ end
+
+ def test_ClassVariableTargetNode
+ assert_location(ClassVariableTargetNode, "@@foo, @@bar = baz", 0...5) do |node|
+ node.lefts.first
+ end
+ end
+
+ def test_ClassVariableWriteNode
+ assert_location(ClassVariableWriteNode, "@@foo = bar")
+ end
+
+ def test_ConstantPathAndWriteNode
+ assert_location(ConstantPathAndWriteNode, "Parent::Child &&= bar")
+ end
+
+ def test_ConstantPathNode
+ assert_location(ConstantPathNode, "Foo::Bar")
+ assert_location(ConstantPathNode, "::Foo")
+ assert_location(ConstantPathNode, "::Foo::Bar")
+ end
+
+ def test_ConstantPathOperatorWriteNode
+ assert_location(ConstantPathOperatorWriteNode, "Parent::Child += bar")
+ end
+
+ def test_ConstantPathOrWriteNode
+ assert_location(ConstantPathOrWriteNode, "Parent::Child ||= bar")
+ end
+
+ def test_ConstantPathTargetNode
+ assert_location(ConstantPathTargetNode, "::Foo, ::Bar = baz", 0...5) do |node|
+ node.lefts.first
+ end
+ end
+
+ def test_ConstantPathWriteNode
+ assert_location(ConstantPathWriteNode, "Foo::Bar = baz")
+ assert_location(ConstantPathWriteNode, "::Foo = bar")
+ assert_location(ConstantPathWriteNode, "::Foo::Bar = baz")
+ end
+
+ def test_ConstantAndWriteNode
+ assert_location(ConstantAndWriteNode, "Foo &&= bar")
+ end
+
+ def test_ConstantOperatorWriteNode
+ assert_location(ConstantOperatorWriteNode, "Foo += bar")
+ end
+
+ def test_ConstantOrWriteNode
+ assert_location(ConstantOrWriteNode, "Foo ||= bar")
+ end
+
+ def test_ConstantReadNode
+ assert_location(ConstantReadNode, "Foo")
+ end
+
+ def test_ConstantTargetNode
+ assert_location(ConstantTargetNode, "Foo, Bar = baz", 0...3) do |node|
+ node.lefts.first
+ end
+ end
+
+ def test_ConstantWriteNode
+ assert_location(ConstantWriteNode, "Foo = bar")
+ end
+
+ def test_DefNode
+ assert_location(DefNode, "def foo; bar; end")
+ assert_location(DefNode, "def foo = bar")
+ assert_location(DefNode, "def foo.bar; baz; end")
+ assert_location(DefNode, "def foo.bar = baz")
+ end
+
+ def test_DefinedNode
+ assert_location(DefinedNode, "defined? foo")
+ assert_location(DefinedNode, "defined?(foo)")
+ end
+
+ def test_ElseNode
+ assert_location(ElseNode, "if foo; bar; else; baz; end", 13...27, &:subsequent)
+ assert_location(ElseNode, "foo ? bar : baz", 10...15, &:subsequent)
+ end
+
+ def test_EmbeddedStatementsNode
+ assert_location(EmbeddedStatementsNode, '"foo #{bar} baz"', 5...11) { |node| node.parts[1] }
+ end
+
+ def test_EmbeddedVariableNode
+ assert_location(EmbeddedVariableNode, '"foo #@@bar baz"', 5...11) { |node| node.parts[1] }
+ end
+
+ def test_EnsureNode
+ assert_location(EnsureNode, "begin; foo; ensure; bar; end", 12...28, &:ensure_clause)
+ end
+
+ def test_FalseNode
+ assert_location(FalseNode, "false")
+ end
+
+ def test_FindPatternNode
+ assert_location(FindPatternNode, "case foo; in *, bar, *; end", 13...22) do |node|
+ node.conditions.first.pattern
+ end
+ end
+
+ def test_FlipFlopNode
+ assert_location(FlipFlopNode, "if foo..bar; end", 3..11, &:predicate)
+ end
+
+ def test_FloatNode
+ assert_location(FloatNode, "0.0")
+ assert_location(FloatNode, "1.0")
+ assert_location(FloatNode, "1.0e10")
+ assert_location(FloatNode, "1.0e-10")
+ end
+
+ def test_ForNode
+ assert_location(ForNode, "for foo in bar; end")
+ assert_location(ForNode, "for foo, bar in baz do end")
+ end
+
+ def test_ForwardingArgumentsNode
+ assert_location(ForwardingArgumentsNode, "def foo(...); bar(...); end", 18...21) do |node|
+ node.body.body.first.arguments.arguments.first
+ end
+ end
+
+ def test_ForwardingParameterNode
+ assert_location(ForwardingParameterNode, "def foo(...); end", 8...11) do |node|
+ node.parameters.keyword_rest
+ end
+ end
+
+ def test_ForwardingSuperNode
+ assert_location(ForwardingSuperNode, "super")
+ assert_location(ForwardingSuperNode, "super {}")
+ end
+
+ def test_GlobalVariableAndWriteNode
+ assert_location(GlobalVariableAndWriteNode, "$foo &&= bar")
+ end
+
+ def test_GlobalVariableOperatorWriteNode
+ assert_location(GlobalVariableOperatorWriteNode, "$foo += bar")
+ end
+
+ def test_GlobalVariableOrWriteNode
+ assert_location(GlobalVariableOrWriteNode, "$foo ||= bar")
+ end
+
+ def test_GlobalVariableReadNode
+ assert_location(GlobalVariableReadNode, "$foo")
+ end
+
+ def test_GlobalVariableTargetNode
+ assert_location(GlobalVariableTargetNode, "$foo, $bar = baz", 0...4) do |node|
+ node.lefts.first
+ end
+ end
+
+ def test_GlobalVariableWriteNode
+ assert_location(GlobalVariableWriteNode, "$foo = bar")
+ end
+
+ def test_HashNode
+ assert_location(HashNode, "{ foo: 2 }")
+ assert_location(HashNode, "{ \nfoo: 2, \nbar: 3 \n}")
+ end
+
+ def test_HashPatternNode
+ assert_location(HashPatternNode, "case foo; in bar: baz; end", 13...21) do |node|
+ node.conditions.first.pattern
+ end
+ end
+
+ def test_IfNode
+ assert_location(IfNode, "if type in 1;elsif type in B;end")
+ end
+
+ def test_ImaginaryNode
+ assert_location(ImaginaryNode, "1i")
+ assert_location(ImaginaryNode, "1ri")
+ end
+
+ def test_ImplicitNode
+ assert_location(ImplicitNode, "{ foo: }", 2...6) do |node|
+ node.elements.first.value
+ end
+
+ assert_location(ImplicitNode, "{ Foo: }", 2..6) do |node|
+ node.elements.first.value
+ end
+
+ assert_location(ImplicitNode, "foo = 1; { foo: }", 11..15) do |node|
+ node.elements.first.value
+ end
+ end
+
+ def test_ImplicitRestNode
+ assert_location(ImplicitRestNode, "foo, = bar", 3..4, &:rest)
+
+ assert_location(ImplicitRestNode, "for foo, in bar do end", 7..8) do |node|
+ node.index.rest
+ end
+
+ assert_location(ImplicitRestNode, "foo { |bar,| }", 10..11) do |node|
+ node.block.parameters.parameters.rest
+ end
+
+ assert_location(ImplicitRestNode, "foo in [bar,]", 11..12) do |node|
+ node.pattern.rest
+ end
+ end
+
+ def test_InNode
+ assert_location(InNode, "case foo; in bar; end", 10...16) do |node|
+ node.conditions.first
+ end
+ end
+
+ def test_IndexAndWriteNode
+ assert_location(IndexAndWriteNode, "foo[foo] &&= bar")
+ end
+
+ def test_IndexOperatorWriteNode
+ assert_location(IndexOperatorWriteNode, "foo[foo] += bar")
+ end
+
+ def test_IndexOrWriteNode
+ assert_location(IndexOrWriteNode, "foo[foo] ||= bar")
+ end
+
+ def test_IndexTargetNode
+ assert_location(IndexTargetNode, "foo[bar], = qux", 0...8) do |node|
+ node.lefts.first
+ end
+ end
+
+ def test_InstanceVariableAndWriteNode
+ assert_location(InstanceVariableAndWriteNode, "@foo &&= bar")
+ end
+
+ def test_InstanceVariableOperatorWriteNode
+ assert_location(InstanceVariableOperatorWriteNode, "@foo += bar")
+ end
+
+ def test_InstanceVariableOrWriteNode
+ assert_location(InstanceVariableOrWriteNode, "@foo ||= bar")
+ end
+
+ def test_InstanceVariableReadNode
+ assert_location(InstanceVariableReadNode, "@foo")
+ end
+
+ def test_InstanceVariableTargetNode
+ assert_location(InstanceVariableTargetNode, "@foo, @bar = baz", 0...4) do |node|
+ node.lefts.first
+ end
+ end
+
+ def test_InstanceVariableWriteNode
+ assert_location(InstanceVariableWriteNode, "@foo = bar")
+ end
+
+ def test_IntegerNode
+ assert_location(IntegerNode, "0")
+ assert_location(IntegerNode, "1")
+ assert_location(IntegerNode, "1_000")
+ assert_location(IntegerNode, "0x1")
+ assert_location(IntegerNode, "0x1_000")
+ assert_location(IntegerNode, "0b1")
+ assert_location(IntegerNode, "0b1_000")
+ assert_location(IntegerNode, "0o1")
+ assert_location(IntegerNode, "0o1_000")
+ end
+
+ def test_InterpolatedMatchLastLineNode
+ assert_location(InterpolatedMatchLastLineNode, "if /foo \#{bar}/ then end", 3...15, &:predicate)
+ end
+
+ def test_InterpolatedRegularExpressionNode
+ assert_location(InterpolatedRegularExpressionNode, "/\#{foo}/")
+ assert_location(InterpolatedRegularExpressionNode, "/\#{foo}/io")
+ end
+
+ def test_InterpolatedStringNode
+ assert_location(InterpolatedStringNode, "\"foo \#@bar baz\"")
+ assert_location(InterpolatedStringNode, "<<~A\nhello \#{1} world\nA", 0...4)
+ assert_location(InterpolatedStringNode, '"foo" "bar"')
+ end
+
+ def test_InterpolatedSymbolNode
+ assert_location(InterpolatedSymbolNode, ':"#{foo}bar"')
+ end
+
+ def test_InterpolatedXStringNode
+ assert_location(InterpolatedXStringNode, '`foo #{bar} baz`')
+ end
+
+ def test_ItLocalVariableReadNode
+ assert_location(ItLocalVariableReadNode, "-> { it }", 5...7) do |node|
+ node.body.body.first
+ end
+
+ assert_location(ItLocalVariableReadNode, "foo { it }", 6...8) do |node|
+ node.block.body.body.first
+ end
+
+ assert_location(CallNode, "-> { it }", 5...7, version: "3.3.0") do |node|
+ node.body.body.first
+ end
+
+ assert_location(ItLocalVariableReadNode, "-> { it }", 5...7, version: "3.4.0") do |node|
+ node.body.body.first
+ end
+ end
+
+ def test_ItParametersNode
+ assert_location(ItParametersNode, "-> { it }", &:parameters)
+ end
+
+ def test_KeywordHashNode
+ assert_location(KeywordHashNode, "foo(a, b: 1)", 7...11) { |node| node.arguments.arguments[1] }
+ end
+
+ def test_KeywordRestParameterNode
+ assert_location(KeywordRestParameterNode, "def foo(**); end", 8...10) do |node|
+ node.parameters.keyword_rest
+ end
+
+ assert_location(KeywordRestParameterNode, "def foo(**bar); end", 8...13) do |node|
+ node.parameters.keyword_rest
+ end
+ end
+
+ def test_LambdaNode
+ assert_location(LambdaNode, "-> { foo }")
+ assert_location(LambdaNode, "-> do foo end")
+ end
+
+ def test_LocalVariableAndWriteNode
+ assert_location(LocalVariableAndWriteNode, "foo &&= bar")
+ assert_location(LocalVariableAndWriteNode, "foo = 1; foo &&= bar", 9...20)
+ end
+
+ def test_LocalVariableOperatorWriteNode
+ assert_location(LocalVariableOperatorWriteNode, "foo += bar")
+ assert_location(LocalVariableOperatorWriteNode, "foo = 1; foo += bar", 9...19)
+ end
+
+ def test_LocalVariableOrWriteNode
+ assert_location(LocalVariableOrWriteNode, "foo ||= bar")
+ assert_location(LocalVariableOrWriteNode, "foo = 1; foo ||= bar", 9...20)
+ end
+
+ def test_LocalVariableReadNode
+ assert_location(LocalVariableReadNode, "foo = 1; foo", 9...12)
+ end
+
+ def test_LocalVariableTargetNode
+ assert_location(LocalVariableTargetNode, "foo, bar = baz", 0...3) do |node|
+ node.lefts.first
+ end
+ end
+
+ def test_LocalVariableWriteNode
+ assert_location(LocalVariableWriteNode, "foo = bar")
+ end
+
+ def test_MatchLastLineNode
+ assert_location(MatchLastLineNode, "if /foo/ then end", 3...8, &:predicate)
+ end
+
+ def test_MatchPredicateNode
+ assert_location(MatchPredicateNode, "foo in bar")
+ end
+
+ def test_MatchRequiredNode
+ assert_location(MatchRequiredNode, "foo => bar")
+ end
+
+ def test_MatchWriteNode
+ assert_location(MatchWriteNode, "/(?<foo>)/ =~ foo")
+ end
+
+ def test_ModuleNode
+ assert_location(ModuleNode, "module Foo end")
+ end
+
+ def test_MultiTargetNode
+ assert_location(MultiTargetNode, "for foo, bar in baz do end", 4...12, &:index)
+ assert_location(MultiTargetNode, "foo, (bar, baz) = qux", 5...15) { |node| node.lefts.last }
+ assert_location(MultiTargetNode, "def foo((bar)); end", 8...13) do |node|
+ node.parameters.requireds.first
+ end
+ end
+
+ def test_MultiWriteNode
+ assert_location(MultiWriteNode, "foo, bar = baz")
+ assert_location(MultiWriteNode, "(foo, bar) = baz")
+ assert_location(MultiWriteNode, "((foo, bar)) = baz")
+ end
+
+ def test_NextNode
+ assert_location(NextNode, "tap { next }", 6...10) { |node| node.block.body.body.first }
+ assert_location(NextNode, "tap { next foo }", 6...14) { |node| node.block.body.body.first }
+ assert_location(NextNode, "tap { next foo, bar }", 6...19) { |node| node.block.body.body.first }
+ assert_location(NextNode, "tap { next(foo) }", 6...15) { |node| node.block.body.body.first }
+ end
+
+ def test_NilNode
+ assert_location(NilNode, "nil")
+ end
+
+ def test_NoBlockParameterNode
+ assert_location(NoBlockParameterNode, "def foo(&nil); end", 8...12) { |node| node.parameters.block }
+ end
+
+ def test_NoKeywordsParameterNode
+ assert_location(NoKeywordsParameterNode, "def foo(**nil); end", 8...13) { |node| node.parameters.keyword_rest }
+ end
+
+ def test_NumberedParametersNode
+ assert_location(NumberedParametersNode, "-> { _1 }", &:parameters)
+ assert_location(NumberedParametersNode, "foo { _1 }", 4...10) { |node| node.block.parameters }
+ end
+
+ def test_NumberedReferenceReadNode
+ assert_location(NumberedReferenceReadNode, "$1")
+ end
+
+ def test_OptionalKeywordParameterNode
+ assert_location(OptionalKeywordParameterNode, "def foo(bar: nil); end", 8...16) do |node|
+ node.parameters.keywords.first
+ end
+ end
+
+ def test_OptionalParameterNode
+ assert_location(OptionalParameterNode, "def foo(bar = nil); end", 8...17) do |node|
+ node.parameters.optionals.first
+ end
+ end
+
+ def test_OrNode
+ assert_location(OrNode, "foo || bar")
+ assert_location(OrNode, "foo or bar")
+ end
+
+ def test_ParametersNode
+ assert_location(ParametersNode, "def foo(bar, baz); end", 8...16, &:parameters)
+ end
+
+ def test_ParenthesesNode
+ assert_location(ParenthesesNode, "()")
+ assert_location(ParenthesesNode, "(foo)")
+ assert_location(ParenthesesNode, "foo (bar), baz", 4...9) { |node| node.arguments.arguments.first }
+ assert_location(ParenthesesNode, "def (foo).bar; end", 4...9, &:receiver)
+ end
+
+ def test_PinnedExpressionNode
+ assert_location(PinnedExpressionNode, "foo in ^(bar)", 7...13, &:pattern)
+ end
+
+ def test_PinnedVariableNode
+ assert_location(PinnedVariableNode, "bar = 1; foo in ^bar", 16...20, &:pattern)
+ assert_location(PinnedVariableNode, "proc { 1 in ^it }.call(1)", 12...15) do |node|
+ node.receiver.block.body.body.first.pattern
+ end
+ end
+
+ def test_PostExecutionNode
+ assert_location(PostExecutionNode, "END {}")
+ assert_location(PostExecutionNode, "END { foo }")
+ end
+
+ def test_PreExecutionNode
+ assert_location(PreExecutionNode, "BEGIN {}")
+ assert_location(PreExecutionNode, "BEGIN { foo }")
+ end
+
+ def test_RangeNode
+ assert_location(RangeNode, "1..2")
+ assert_location(RangeNode, "1...2")
+
+ assert_location(RangeNode, "..2")
+ assert_location(RangeNode, "...2")
+
+ assert_location(RangeNode, "1..")
+ assert_location(RangeNode, "1...")
+ end
+
+ def test_RationalNode
+ assert_location(RationalNode, "1r")
+ assert_location(RationalNode, "1.0r")
+ end
+
+ def test_RedoNode
+ assert_location(RedoNode, "tap { redo }", 6...10) { |node| node.block.body.body.first }
+ end
+
+ def test_RegularExpressionNode
+ assert_location(RegularExpressionNode, "/foo/")
+ assert_location(RegularExpressionNode, "/foo/io")
+ end
+
+ def test_RequiredKeywordParameterNode
+ assert_location(RequiredKeywordParameterNode, "def foo(bar:); end", 8...12) do |node|
+ node.parameters.keywords.first
+ end
+ end
+
+ def test_RequiredParameterNode
+ assert_location(RequiredParameterNode, "def foo(bar); end", 8...11) do |node|
+ node.parameters.requireds.first
+ end
+ end
+
+ def test_RescueNode
+ code = <<~RUBY
+ begin
+ body
+ rescue TypeError
+ rescue ArgumentError
+ end
+ RUBY
+ assert_location(RescueNode, code, 13...50) { |node| node.rescue_clause }
+ assert_location(RescueNode, code, 30...50) { |node| node.rescue_clause.subsequent }
+ end
+
+ def test_RescueModifierNode
+ assert_location(RescueModifierNode, "foo rescue bar")
+ end
+
+ def test_RestParameterNode
+ assert_location(RestParameterNode, "def foo(*bar); end", 8...12) do |node|
+ node.parameters.rest
+ end
+ end
+
+ def test_RetryNode
+ assert_location(RetryNode, "begin; rescue; retry; end", 15...20) { |node| node.rescue_clause.statements.body.first }
+ end
+
+ def test_ReturnNode
+ assert_location(ReturnNode, "return")
+ assert_location(ReturnNode, "return foo")
+ assert_location(ReturnNode, "return foo, bar")
+ assert_location(ReturnNode, "return(foo)")
+ end
+
+ def test_SelfNode
+ assert_location(SelfNode, "self")
+ end
+
+ def test_ShareableConstantNode
+ source = <<~RUBY
+ # shareable_constant_value: literal
+ C = { foo: 1 }
+ RUBY
+
+ assert_location(ShareableConstantNode, source, 36...50)
+ end
+
+ def test_SingletonClassNode
+ assert_location(SingletonClassNode, "class << self; end")
+ end
+
+ def test_SourceEncodingNode
+ assert_location(SourceEncodingNode, "__ENCODING__")
+ end
+
+ def test_SourceFileNode
+ assert_location(SourceFileNode, "__FILE__")
+ end
+
+ def test_SourceLineNode
+ assert_location(SourceLineNode, "__LINE__")
+ end
+
+ def test_SplatNode
+ assert_location(SplatNode, "*foo = bar", 0...4, &:rest)
+ end
+
+ def test_StatementsNode
+ assert_location(StatementsNode, "foo { 1 }", 6...7) { |node| node.block.body }
+
+ assert_location(StatementsNode, "(1)", 1...2, &:body)
+
+ assert_location(StatementsNode, "def foo; 1; end", 9...10, &:body)
+ assert_location(StatementsNode, "def foo = 1", 10...11, &:body)
+ assert_location(StatementsNode, "def foo; 1\n2; end", 9...12, &:body)
+
+ assert_location(StatementsNode, "if foo; bar; end", 8...11, &:statements)
+ assert_location(StatementsNode, "foo if bar", 0...3, &:statements)
+
+ assert_location(StatementsNode, "if foo; foo; elsif bar; bar; end", 24...27) { |node| node.subsequent.statements }
+ assert_location(StatementsNode, "if foo; foo; else; bar; end", 19...22) { |node| node.subsequent.statements }
+
+ assert_location(StatementsNode, "unless foo; bar; end", 12...15, &:statements)
+ assert_location(StatementsNode, "foo unless bar", 0...3, &:statements)
+
+ assert_location(StatementsNode, "case; when foo; bar; end", 16...19) { |node| node.conditions.first.statements }
+
+ assert_location(StatementsNode, "while foo; bar; end", 11...14, &:statements)
+ assert_location(StatementsNode, "foo while bar", 0...3, &:statements)
+
+ assert_location(StatementsNode, "until foo; bar; end", 11...14, &:statements)
+ assert_location(StatementsNode, "foo until bar", 0...3, &:statements)
+
+ assert_location(StatementsNode, "for foo in bar; baz; end", 16...19, &:statements)
+
+ assert_location(StatementsNode, "begin; foo; end", 7...10, &:statements)
+ assert_location(StatementsNode, "begin; rescue; foo; end", 15...18) { |node| node.rescue_clause.statements }
+ assert_location(StatementsNode, "begin; ensure; foo; end", 15...18) { |node| node.ensure_clause.statements }
+ assert_location(StatementsNode, "begin; rescue; else; foo; end", 21...24) { |node| node.else_clause.statements }
+
+ assert_location(StatementsNode, "class Foo; foo; end", 11...14, &:body)
+ assert_location(StatementsNode, "module Foo; foo; end", 12...15, &:body)
+ assert_location(StatementsNode, "class << self; foo; end", 15...18, &:body)
+
+ assert_location(StatementsNode, "-> { foo }", 5...8, &:body)
+ assert_location(StatementsNode, "BEGIN { foo }", 8...11, &:statements)
+ assert_location(StatementsNode, "END { foo }", 6...9, &:statements)
+
+ assert_location(StatementsNode, "\"\#{foo}\"", 3...6) { |node| node.parts.first.statements }
+ end
+
+ def test_StringNode
+ assert_location(StringNode, '"foo"')
+ assert_location(StringNode, '%q[foo]')
+ end
+
+ def test_SuperNode
+ assert_location(SuperNode, "super foo")
+ assert_location(SuperNode, "super foo, bar")
+
+ assert_location(SuperNode, "super()")
+ assert_location(SuperNode, "super(foo)")
+ assert_location(SuperNode, "super(foo, bar)")
+
+ assert_location(SuperNode, "super() {}")
+ end
+
+ def test_SymbolNode
+ assert_location(SymbolNode, ":foo")
+ end
+
+ def test_TrueNode
+ assert_location(TrueNode, "true")
+ end
+
+ def test_UndefNode
+ assert_location(UndefNode, "undef foo")
+ assert_location(UndefNode, "undef foo, bar")
+ end
+
+ def test_UnlessNode
+ assert_location(UnlessNode, "foo unless bar")
+ assert_location(UnlessNode, "unless bar; foo; end")
+ end
+
+ def test_UntilNode
+ assert_location(UntilNode, "foo = bar until baz")
+ assert_location(UntilNode, "until bar;baz;end")
+ end
+
+ def test_WhenNode
+ assert_location(WhenNode, "case foo; when bar; end", 10...18) { |node| node.conditions.first }
+ end
+
+ def test_WhileNode
+ assert_location(WhileNode, "foo = bar while foo != baz")
+ assert_location(WhileNode, "while a;bar;baz;end")
+ end
+
+ def test_XStringNode
+ assert_location(XStringNode, "`foo`")
+ assert_location(XStringNode, "%x[foo]")
+ end
+
+ def test_YieldNode
+ assert_location(YieldNode, "def test; yield; end", 10...15) { |node| node.body.body.first }
+ assert_location(YieldNode, "def test; yield foo; end", 10...19) { |node| node.body.body.first }
+ assert_location(YieldNode, "def test; yield foo, bar; end", 10...24) { |node| node.body.body.first }
+ assert_location(YieldNode, "def test; yield(foo); end", 10...20) { |node| node.body.body.first }
+ end
+
+ def test_all_tested
+ expected = Prism.constants.grep(/.Node$/).sort - %i[ErrorRecoveryNode ProgramNode]
+ actual = SourceLocationTest.instance_methods(false).grep(/.Node$/).map { |name| name[5..].to_sym }.sort
+ assert_equal expected, actual
+ end
+
+ private
+
+ def assert_location(kind, source, expected = 0...source.length, **options)
+ result = Prism.parse(source, **options)
+ assert result.success?
+
+ node = result.value.statements.body.last
+ node = yield node if block_given?
+
+ if expected.begin == 0
+ assert_equal 0, node.location.start_column, "#{kind} start_column"
+ end
+
+ if expected.end == source.length
+ assert_equal source.split("\n").last.length, node.location.end_column, "#{kind} end_column"
+ end
+
+ assert_kind_of kind, node
+ assert_equal expected.begin, node.location.start_offset, "#{kind} start_offset"
+ assert_equal expected.end, node.location.end_offset, "#{kind} end_offset"
+ end
+ end
+end
diff --git a/test/prism/result/static_inspect_test.rb b/test/prism/result/static_inspect_test.rb
new file mode 100644
index 0000000000..cf8cef3298
--- /dev/null
+++ b/test/prism/result/static_inspect_test.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class StaticInspectTest < TestCase
+ def test_false
+ assert_equal "false", static_inspect("false")
+ end
+
+ def test_float
+ assert_equal "0.25", static_inspect("0.25")
+ assert_equal "5.125", static_inspect("5.125")
+
+ assert_equal "0.0", static_inspect("0.0")
+ assert_equal "-0.0", static_inspect("-0.0")
+
+ assert_equal "1.0e+100", static_inspect("1e100")
+ assert_equal "-1.0e+100", static_inspect("-1e100")
+
+ assert_equal "Infinity", static_inspect("1e1000")
+ assert_equal "-Infinity", static_inspect("-1e1000")
+ end
+
+ def test_imaginary
+ assert_equal "(0+1i)", static_inspect("1i")
+ assert_equal "(0-1i)", static_inspect("-1i")
+ end
+
+ def test_integer
+ assert_equal "1000", static_inspect("1_0_0_0")
+ assert_equal "10000000000000000000000000000", static_inspect("1_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0")
+ end
+
+ def test_nil
+ assert_equal "nil", static_inspect("nil")
+ end
+
+ def test_rational
+ assert_equal "(0/1)", static_inspect("0r")
+ assert_equal "(1/1)", static_inspect("1r")
+ assert_equal "(1/1)", static_inspect("1.0r")
+ assert_equal "(77777/1000)", static_inspect("77.777r")
+ end
+
+ def test_regular_expression
+ assert_equal "/.*/", static_inspect("/.*/")
+ assert_equal "/.*/i", static_inspect("/.*/i")
+ assert_equal "/.*/", static_inspect("/.*/u")
+ assert_equal "/.*/n", static_inspect("/.*/un")
+ end
+
+ def test_source_encoding
+ assert_equal "#<Encoding:UTF-8>", static_inspect("__ENCODING__")
+ assert_equal "#<Encoding:Windows-31J>", static_inspect("__ENCODING__", encoding: "Windows-31J")
+ end
+
+ def test_source_file
+ assert_equal __FILE__.inspect, static_inspect("__FILE__", filepath: __FILE__, frozen_string_literal: true)
+ end
+
+ def test_source_line
+ assert_equal "1", static_inspect("__LINE__")
+ assert_equal "5", static_inspect("__LINE__", line: 5)
+ end
+
+ def test_string
+ assert_equal "\"\"", static_inspect('""', frozen_string_literal: true)
+ assert_equal "\"Hello, World!\"", static_inspect('"Hello, World!"', frozen_string_literal: true)
+ assert_equal "\"\\a\"", static_inspect("\"\\a\"", frozen_string_literal: true)
+ end
+
+ def test_symbol
+ assert_equal ":foo", static_inspect(":foo")
+ assert_equal ":foo", static_inspect("%s[foo]")
+ end
+
+ def test_true
+ assert_equal "true", static_inspect("true")
+ end
+
+ private
+
+ def static_inspect(source, **options)
+ warnings = Prism.parse("{ #{source} => 1, #{source} => 1 }", **options).warnings
+ warnings.last.message[/^key (.+) is duplicated and overwritten on line \d/, 1]
+ end
+ end
+end
diff --git a/test/prism/result/static_literals_test.rb b/test/prism/result/static_literals_test.rb
new file mode 100644
index 0000000000..dcfc692897
--- /dev/null
+++ b/test/prism/result/static_literals_test.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class StaticLiteralsTest < TestCase
+ def test_static_literals
+ assert_warning("1")
+ assert_warning("0xA", "10", "10")
+ assert_warning("0o10", "8", "8")
+ assert_warning("0b10", "2", "2")
+ assert_warning("1_000", "1000", "1000")
+ assert_warning((2**32).to_s(10), "0x#{(2**32).to_s(16)}", (2**32).to_s(10))
+ assert_warning((2**64).to_s(10), "0x#{(2**64).to_s(16)}", (2**64).to_s(10))
+
+ refute_warning("1", "-1")
+ refute_warning((2**32).to_s(10), "-0x#{(2**32).to_s(16)}")
+ refute_warning((2**64).to_s(10), "-0x#{(2**64).to_s(16)}")
+
+ assert_warning("__LINE__", "2", "2")
+ assert_warning("3", "__LINE__", "3")
+
+ assert_warning("1.0")
+ assert_warning("1e2", "100.0", "100.0")
+
+ assert_warning("1r", "1r", "(1/1)")
+ assert_warning("1.0r", "1.0r", "(1/1)")
+
+ assert_warning("1i", "1i", "(0+1i)")
+ assert_warning("1.0i", "1.0i", "(0+1.0i)")
+
+ assert_warning("1ri", "1ri", "(0+(1/1)*i)")
+ assert_warning("1.0ri", "1.0ri", "(0+(1/1)*i)")
+
+ assert_warning("__FILE__", "\"#{__FILE__}\"", __FILE__)
+ assert_warning("\"#{__FILE__}\"")
+ assert_warning("\"foo\"")
+
+ assert_warning("/foo/")
+
+ refute_warning("/foo/", "/foo/i")
+
+ assert_warning(":foo")
+ assert_warning("%s[foo]", ":foo", ":foo")
+
+ assert_warning("true")
+ assert_warning("false")
+ assert_warning("nil")
+ assert_warning("__ENCODING__", "__ENCODING__", "#<Encoding:UTF-8>")
+ end
+
+ private
+
+ class NullWarning
+ def message
+ ""
+ end
+ end
+
+ def parse_warnings(left, right)
+ warnings = []
+
+ warnings << (Prism.parse(<<~RUBY, filepath: __FILE__).warnings.first || NullWarning.new)
+ {
+ #{left} => 1,
+ #{right} => 2
+ }
+ RUBY
+
+ warnings << (Prism.parse(<<~RUBY, filepath: __FILE__).warnings.first || NullWarning.new)
+ case foo
+ when #{left}
+ when #{right}
+ end
+ RUBY
+
+ warnings
+ end
+
+ def assert_warning(left, right = left, message = left)
+ hash_keys, when_clauses = parse_warnings(left, right)
+
+ assert_include hash_keys.message, message
+ assert_include hash_keys.message, "line 3"
+ assert_include when_clauses.message, "line 3"
+ end
+
+ def refute_warning(left, right)
+ assert_empty parse_warnings(left, right).grep_v(NullWarning)
+ end
+ end
+end
diff --git a/test/prism/result/string_test.rb b/test/prism/result/string_test.rb
new file mode 100644
index 0000000000..48c7f592eb
--- /dev/null
+++ b/test/prism/result/string_test.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class StringTest < TestCase
+ def test_regular_expression_node_unescaped_frozen
+ node = Prism.parse_statement("/foo/")
+ assert_predicate node.unescaped, :frozen?
+ end
+
+ def test_source_file_node_filepath_frozen
+ node = Prism.parse_statement("__FILE__")
+ assert_predicate node.filepath, :frozen?
+ end
+
+ def test_string_node_unescaped_frozen
+ node = Prism.parse_statement('"foo"')
+ assert_predicate node.unescaped, :frozen?
+ end
+
+ def test_symbol_node_unescaped_frozen
+ node = Prism.parse_statement(":foo")
+ assert_predicate node.unescaped, :frozen?
+ end
+
+ def test_xstring_node_unescaped_frozen
+ node = Prism.parse_statement("`foo`")
+ assert_predicate node.unescaped, :frozen?
+ end
+ end
+end
diff --git a/test/prism/result/warnings_test.rb b/test/prism/result/warnings_test.rb
new file mode 100644
index 0000000000..27f1119b98
--- /dev/null
+++ b/test/prism/result/warnings_test.rb
@@ -0,0 +1,451 @@
+# frozen_string_literal: true
+
+return if RUBY_VERSION < "3.1"
+
+require_relative "../test_helper"
+
+module Prism
+ class WarningsTest < TestCase
+ def test_ambiguous_uminus
+ assert_warning("a -b", "ambiguous first argument")
+ end
+
+ def test_ambiguous_uplus
+ assert_warning("a +b", "ambiguous first argument")
+ end
+
+ def test_ambiguous_ustar
+ assert_warning("a *b", "argument prefix")
+ end
+
+ def test_ambiguous_regexp
+ assert_warning("a /b/", "wrap regexp in parentheses")
+ end
+
+ def test_ambiguous_ampersand
+ assert_warning("a &b", "argument prefix")
+ assert_warning("a &:+", "argument prefix")
+
+ refute_warning("a &:b")
+ refute_warning("a &:'b'")
+ refute_warning("a &:\"b\"")
+ end
+
+ def test_binary_operator
+ [
+ [:**, "argument prefix"],
+ [:*, "argument prefix"],
+ [:<<, "here document"],
+ [:&, "argument prefix"],
+ [:+, "unary operator"],
+ [:-, "unary operator"],
+ [:/, "regexp literal"],
+ [:%, "string literal"]
+ ].each do |(operator, warning)|
+ assert_warning("puts 1 #{operator}0", warning)
+ assert_warning("puts :a #{operator}0", warning)
+ assert_warning("m = 1; puts m #{operator}0", warning)
+ end
+ end
+
+ def test_equal_in_conditional
+ assert_warning("if a = 1; end; a = a", "should be ==")
+ end
+
+ def test_dot_dot_dot_eol
+ assert_warning("_ = foo...", "... at EOL")
+ assert_warning("def foo(...) = bar ...", "... at EOL")
+
+ assert_warning("_ = foo... #", "... at EOL")
+ assert_warning("_ = foo... \t\v\f\n", "... at EOL")
+
+ refute_warning("p foo...bar")
+ refute_warning("p foo... bar")
+ end
+
+ def test_END_in_method
+ assert_warning("def foo; END {}; end", "END in method")
+ end
+
+ def test_duplicated_hash_key
+ assert_warning("{ a: 1, a: 2 }", "duplicated and overwritten")
+ assert_warning("{ a: 1, **{ a: 2 } }", "duplicated and overwritten")
+ end
+
+ def test_duplicated_when_clause
+ assert_warning("case 1; when 1, 1; end", "when' clause")
+ end
+
+ def test_float_out_of_range
+ assert_warning("_ = 1.0e100000", "out of range")
+ end
+
+ def test_indentation_mismatch
+ assert_warning("if true\n end", "mismatched indentations at 'end' with 'if'")
+ assert_warning("if true\n elsif true\nend", "mismatched indentations at 'elsif' with 'if'")
+ assert_warning("if true\n else\nend", "mismatched indentations at 'else' with 'if'", "mismatched indentations at 'end' with 'else'")
+
+ assert_warning("unless true\n end", "mismatched indentations at 'end' with 'unless'")
+ assert_warning("unless true\n else\nend", "mismatched indentations at 'else' with 'unless'", "mismatched indentations at 'end' with 'else'")
+
+ assert_warning("while true\n end", "mismatched indentations at 'end' with 'while'")
+ assert_warning("until true\n end", "mismatched indentations at 'end' with 'until'")
+
+ assert_warning("begin\n end", "mismatched indentations at 'end' with 'begin'")
+ assert_warning("begin\n rescue\nend", "mismatched indentations at 'rescue' with 'begin'")
+ assert_warning("begin\n ensure\nend", "mismatched indentations at 'ensure' with 'begin'")
+ assert_warning("begin\nrescue\n else\nend", "mismatched indentations at 'else' with 'begin'", "mismatched indentations at 'end' with 'else'")
+ assert_warning("begin\n rescue\n ensure\n end", "mismatched indentations at 'rescue' with 'begin'", "mismatched indentations at 'ensure' with 'begin'", "mismatched indentations at 'end' with 'begin'");
+
+ assert_warning("def foo\n end", "mismatched indentations at 'end' with 'def'")
+ assert_warning("def foo\n rescue\nend", "mismatched indentations at 'rescue' with 'def'")
+ assert_warning("def foo\n ensure\nend", "mismatched indentations at 'ensure' with 'def'")
+ assert_warning("def foo\nrescue\n else\nend", "mismatched indentations at 'else' with 'def'", "mismatched indentations at 'end' with 'else'")
+ assert_warning("def foo\n rescue\n ensure\n end", "mismatched indentations at 'rescue' with 'def'", "mismatched indentations at 'ensure' with 'def'", "mismatched indentations at 'end' with 'def'");
+
+ assert_warning("class Foo\n end", "mismatched indentations at 'end' with 'class'")
+ assert_warning("class Foo\n rescue\nend", "mismatched indentations at 'rescue' with 'class'")
+ assert_warning("class Foo\n ensure\nend", "mismatched indentations at 'ensure' with 'class'")
+ assert_warning("class Foo\nrescue\n else\nend", "mismatched indentations at 'else' with 'class'", "mismatched indentations at 'end' with 'else'")
+ assert_warning("class Foo\n rescue\n ensure\n end", "mismatched indentations at 'rescue' with 'class'", "mismatched indentations at 'ensure' with 'class'", "mismatched indentations at 'end' with 'class'");
+
+ assert_warning("module Foo\n end", "mismatched indentations at 'end' with 'module'")
+ assert_warning("module Foo\n rescue\nend", "mismatched indentations at 'rescue' with 'module'")
+ assert_warning("module Foo\n ensure\nend", "mismatched indentations at 'ensure' with 'module'")
+ assert_warning("module Foo\nrescue\n else\nend", "mismatched indentations at 'else' with 'module'", "mismatched indentations at 'end' with 'else'")
+ assert_warning("module Foo\n rescue\n ensure\n end", "mismatched indentations at 'rescue' with 'module'", "mismatched indentations at 'ensure' with 'module'", "mismatched indentations at 'end' with 'module'");
+
+ assert_warning("class << foo\n end", "mismatched indentations at 'end' with 'class'")
+ assert_warning("class << foo\n rescue\nend", "mismatched indentations at 'rescue' with 'class'")
+ assert_warning("class << foo\n ensure\nend", "mismatched indentations at 'ensure' with 'class'")
+ assert_warning("class << foo\nrescue\n else\nend", "mismatched indentations at 'else' with 'class'", "mismatched indentations at 'end' with 'else'")
+ assert_warning("class << foo\n rescue\n ensure\n end", "mismatched indentations at 'rescue' with 'class'", "mismatched indentations at 'ensure' with 'class'", "mismatched indentations at 'end' with 'class'");
+
+ assert_warning("case 1; when 2\n end", "mismatched indentations at 'end' with 'case'")
+ assert_warning("case 1; in 2\n end", "mismatched indentations at 'end' with 'case'")
+
+ assert_warning(" case 1\nwhen 2\n end", "mismatched indentations at 'when' with 'case'")
+ refute_warning("case 1\n when 2\n when 3\nend") # case/when allows more indentation
+
+ assert_warning("-> {\n }", "mismatched indentations at '}' with '->'")
+ assert_warning("-> do\n end", "mismatched indentations at 'end' with '->'")
+ assert_warning("-> do\n rescue\nend", "mismatched indentations at 'rescue' with '->'")
+ assert_warning("-> do\n ensure\nend", "mismatched indentations at 'ensure' with '->'")
+ assert_warning("-> do\nrescue\n else\nend", "mismatched indentations at 'else' with '->'", "mismatched indentations at 'end' with 'else'")
+ assert_warning("-> do\n rescue\n ensure\n end", "mismatched indentations at 'rescue' with '->'", "mismatched indentations at 'ensure' with '->'", "mismatched indentations at 'end' with '->'");
+ assert_warning("foo do\nrescue\n else\nend", "mismatched indentations at 'end' with 'else'")
+
+ refute_warning("class Foo; end") # same line
+ refute_warning("; class Foo\nend") # non whitespace on opening line
+ refute_warning("\tclass Foo\n end") # tab stop matches space
+ refute_warning(" \tclass Foo\n end") # tab stop matches space
+ end
+
+ def test_integer_in_flip_flop
+ assert_warning("1 if 2..foo", "integer")
+ end
+
+ def test_literal_in_conditionals
+ sources = [
+ "if (a = 2); a; end",
+ "if ($a = 2); end",
+ "if (@a = 2); end",
+ "if a; elsif b = 2; b end",
+ "unless (a = 2); a; end",
+ "unless ($a = 2); end",
+ "unless (@a = 2); end",
+ "while (a = 2); a; end",
+ "while ($a = 2); end",
+ "while (@a = 2); end",
+ "until (a = 2); a; end",
+ "until ($a = 2); end",
+ "until (@a = 2); end",
+ "foo if (a, b = 2); [a, b]",
+ "foo if a = 2 and a",
+ "(@foo = 1) ? a : b",
+ "!(a = 2) and a",
+ "not a = 2 and a"
+ ]
+
+ if RUBY_VERSION >= "3.3"
+ sources.push(
+ "if (@@a = 2); end",
+ "unless (@@a = 2); end",
+ "while (@@a = 2); end",
+ "until (@@a = 2); end"
+ )
+ end
+
+ sources.each do |source|
+ assert_warning(source, "= literal' in conditional, should be ==")
+ end
+ end
+
+ def test_keyword_eol
+ assert_warning("if\ntrue; end", "end of line")
+ assert_warning("if true\nelsif\nfalse; end", "end of line")
+ end
+
+ def test_numbered_reference
+ assert_warning("_ = _ = $999999999999999999999", "too big for a number variable, always nil")
+ end
+
+ def test_shareable_constant_value
+ assert_warning("foo # shareable_constant_value: none", "ignored")
+ assert_warning("\v # shareable_constant_value: none", "ignored")
+
+ refute_warning("# shareable_constant_value: none")
+ refute_warning(" # shareable_constant_value: none")
+ refute_warning("\t\t# shareable_constant_value: none")
+ end
+
+ def test_string_in_predicate
+ assert_warning("if 'foo'; end", "string")
+ assert_warning("if \"\#{foo}\"; end", "string")
+ assert_warning("if __FILE__; end", "string")
+ end
+
+ def test_symbol_in_predicate
+ assert_warning("if :foo; end", "symbol")
+ assert_warning("if :\"\#{foo}\"; end", "symbol")
+ end
+
+ def test_literal_in_predicate
+ assert_warning("if __LINE__; end", "literal")
+ assert_warning("if __ENCODING__; end", "literal")
+ assert_warning("if 1; end", "literal")
+ assert_warning("if 1.0; end", "literal")
+ assert_warning("if 1r; end", "literal")
+ assert_warning("if 1i; end", "literal")
+ end
+
+ def test_regexp_in_predicate
+ assert_warning("if /foo/; end", "regex")
+ assert_warning("if /foo\#{bar}/; end", "regex")
+ end
+
+ def test_unused_local_variables
+ assert_warning("foo = 1", "unused")
+
+ refute_warning("foo = 1", compare: false, command_line: "e")
+ refute_warning("foo = 1", compare: false, scopes: [[]])
+
+ refute_warning("foo(bar = 1)")
+
+ assert_warning("def foo; bar = 1; end", "unused")
+ assert_warning("def foo; bar, = 1; end", "unused")
+
+ refute_warning("def foo; bar &&= 1; end")
+ refute_warning("def foo; bar ||= 1; end")
+ refute_warning("def foo; bar += 1; end")
+
+ refute_warning("def foo; bar = bar; end")
+ refute_warning("def foo; bar = bar = 1; end")
+ refute_warning("def foo; bar = (bar = 1); end")
+ refute_warning("def foo; bar = begin; bar = 1; end; end")
+ refute_warning("def foo; bar = (qux; bar = 1); end")
+ refute_warning("def foo; bar, = bar = 1; end")
+ refute_warning("def foo; bar, = 1, bar = 1; end")
+
+ refute_warning("def foo(bar); end")
+ refute_warning("def foo(bar = 1); end")
+ refute_warning("def foo((bar)); end")
+ refute_warning("def foo(*bar); end")
+ refute_warning("def foo(*, bar); end")
+ refute_warning("def foo(*, (bar)); end")
+ refute_warning("def foo(bar:); end")
+ refute_warning("def foo(**bar); end")
+ refute_warning("def foo(&bar); end")
+ refute_warning("->(bar) {}")
+ refute_warning("->(; bar) {}", compare: false)
+
+ refute_warning("def foo; bar = 1; tap { bar }; end")
+ refute_warning("def foo; bar = 1; tap { baz = bar; baz }; end")
+
+ refute_warning("def foo; bar = 1; end", line: -2, compare: false)
+ end
+
+ def test_unused_local_variable_or_assign_with_begin_node
+ assert_warning(<<~RUBY, "assigned but unused variable - foo", compare: false)
+ var ||= begin
+ foo = bar
+ baz
+ end
+ RUBY
+
+ assert_warning(<<~RUBY, "assigned but unused variable - foo", compare: false)
+ foo = false
+ var ||= begin
+ foo = true
+ bar
+ end
+ RUBY
+ end
+
+ def test_void_statements
+ assert_warning("foo = 1; foo", "a variable in void")
+ assert_warning("@foo", "a variable in void")
+ assert_warning("@@foo", "a variable in void")
+ assert_warning("$foo", "a variable in void")
+ assert_warning("$+", "a variable in void")
+ assert_warning("$1", "a variable in void")
+
+ assert_warning("self", "self in void")
+ assert_warning("nil", "nil in void")
+ assert_warning("true", "true in void")
+ assert_warning("false", "false in void")
+
+ assert_warning("1", "literal in void")
+ assert_warning("1.0", "literal in void")
+ assert_warning("1r", "literal in void")
+ assert_warning("1i", "literal in void")
+ assert_warning(":foo", "literal in void")
+ assert_warning("\"foo\"", "literal in void")
+ assert_warning("\"foo\#{1}\"", "literal in void")
+ assert_warning("/foo/", "literal in void")
+ assert_warning("/foo\#{1}/", "literal in void")
+
+ assert_warning("Foo", "constant in void")
+ assert_warning("::Foo", ":: in void")
+ assert_warning("Foo::Bar", ":: in void")
+
+ assert_warning("1..2", ".. in void")
+ assert_warning("1..", ".. in void")
+ assert_warning("..2", ".. in void")
+ assert_warning("1...2", "... in void")
+ assert_warning("1...;", "... in void")
+ assert_warning("...2", "... in void")
+
+ assert_warning("defined?(foo)", "defined? in void")
+
+ assert_warning("1 + 1", "+ in void")
+ assert_warning("1 - 1", "- in void")
+ assert_warning("1 * 1", "* in void")
+ assert_warning("1 / 1", "/ in void")
+ assert_warning("1 % 1", "% in void")
+ assert_warning("1 | 1", "| in void")
+ assert_warning("1 ^ 1", "^ in void")
+ assert_warning("1 & 1", "& in void")
+ assert_warning("1 > 1", "> in void")
+ assert_warning("1 < 1", "< in void")
+
+ assert_warning("1 ** 1", "** in void")
+ assert_warning("1 <= 1", "<= in void")
+ assert_warning("1 >= 1", ">= in void")
+ assert_warning("1 != 1", "!= in void")
+ assert_warning("1 == 1", "== in void")
+ assert_warning("1 <=> 1", "<=> in void")
+
+ assert_warning("+foo", "+@ in void")
+ assert_warning("-foo", "-@ in void")
+
+ assert_warning("def foo; @bar; @baz; end", "variable in void")
+ refute_warning("def foo; @bar; end")
+ refute_warning("@foo", compare: false, scopes: [[]])
+ end
+
+ def test_unreachable_statement
+ assert_warning("begin; rescue; retry; foo; end", "statement not reached")
+
+ assert_warning("return; foo", "statement not reached")
+
+ assert_warning("tap { break; foo }", "statement not reached")
+ assert_warning("tap { break 1; foo }", "statement not reached")
+
+ assert_warning("tap { next; foo }", "statement not reached")
+ assert_warning("tap { next 1; foo }", "statement not reached")
+
+ assert_warning("tap { redo; foo }", "statement not reached")
+ end
+
+ if windows?
+ def test_shebang_ending_with_carriage_return
+ refute_warning("#!ruby\r\np(123)\n", compare: false)
+ end
+ else
+ def test_shebang_ending_with_carriage_return
+ msg = "shebang line ending with \\r may cause problems"
+
+ assert_warning(<<~RUBY, msg, compare: false, main_script: true)
+ #!ruby\r
+ p(123)
+ RUBY
+
+ assert_warning(<<~RUBY, msg, compare: false, main_script: true)
+ #!ruby \r
+ p(123)
+ RUBY
+
+ assert_warning(<<~RUBY, msg, compare: false, main_script: true)
+ #!ruby -Eutf-8\r
+ p(123)
+ RUBY
+
+ # Used with the `-x` object, to ignore the script up until the first
+ # shebang that mentioned "ruby".
+ assert_warning(<<~SCRIPT, msg, compare: false, main_script: true)
+ #!/usr/bin/env bash
+ # Some initial shell script or other content
+ # that Ruby should ignore
+ echo "This is shell script part"
+ exit 0
+
+ #! /usr/bin/env ruby -Eutf-8\r
+ # Ruby script starts here
+ puts "Hello from Ruby!"
+ SCRIPT
+
+ refute_warning("#ruby not_a_shebang\r\n", compare: false, main_script: true)
+
+ # CRuby doesn't emit the warning if a malformed file only has `\r` and
+ # not `\n`. https://bugs.ruby-lang.org/issues/20700.
+ refute_warning("#!ruby\r", compare: false, main_script: true)
+ end
+ end
+
+ def test_warnings_verbosity
+ warning = Prism.parse("def foo; END { }; end").warnings.first
+ assert_equal "END in method; use at_exit", warning.message
+ assert_equal :default, warning.level
+
+ warning = Prism.parse("foo /regexp/").warnings.first
+ assert_equal "ambiguous `/`; wrap regexp in parentheses or add a space after `/` operator", warning.message
+ assert_equal :verbose, warning.level
+ end
+
+ private
+
+ def assert_warning(source, *messages, compare: true, **options)
+ warnings = Prism.parse(source, **options).warnings
+ assert_equal messages.length, warnings.length, "Expected #{messages.length} warning(s) in #{source.inspect}, got #{warnings.map(&:message).inspect}"
+
+ warnings.zip(messages).each do |warning, message|
+ assert_include warning.message, message
+ end
+
+ if compare && defined?(RubyVM::AbstractSyntaxTree)
+ stderr = capture_stderr { RubyVM::AbstractSyntaxTree.parse(source) }
+ messages.each { |message| assert_include stderr, message }
+ end
+ end
+
+ def refute_warning(source, compare: true, **options)
+ assert_empty Prism.parse(source, **options).warnings
+
+ if compare && defined?(RubyVM::AbstractSyntaxTree)
+ assert_empty capture_stderr { RubyVM::AbstractSyntaxTree.parse(source) }
+ end
+ end
+
+ def capture_stderr
+ stderr, $stderr, verbose, $VERBOSE = $stderr, StringIO.new, $VERBOSE, true
+
+ begin
+ yield
+ $stderr.string
+ ensure
+ $stderr, $VERBOSE = stderr, verbose
+ end
+ end
+ end
+end
diff --git a/test/prism/ruby/compiler_test.rb b/test/prism/ruby/compiler_test.rb
new file mode 100644
index 0000000000..35ccfd5950
--- /dev/null
+++ b/test/prism/ruby/compiler_test.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+# typed: ignore
+
+require_relative "../test_helper"
+
+module Prism
+ class CompilerTest < TestCase
+ class SExpressions < Prism::Compiler
+ def visit_arguments_node(node)
+ [:arguments, super]
+ end
+
+ def visit_call_node(node)
+ [:call, super]
+ end
+
+ def visit_integer_node(node)
+ [:integer]
+ end
+
+ def visit_program_node(node)
+ [:program, super]
+ end
+ end
+
+ def test_compiler
+ expected = [:program, [[[:call, [[:integer], [:arguments, [[:integer]]]]]]]]
+ assert_equal expected, Prism.parse("1 + 2").value.accept(SExpressions.new)
+ end
+ end
+end
diff --git a/test/prism/ruby/desugar_compiler_test.rb b/test/prism/ruby/desugar_compiler_test.rb
new file mode 100644
index 0000000000..fe9a25e030
--- /dev/null
+++ b/test/prism/ruby/desugar_compiler_test.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class DesugarCompilerTest < TestCase
+ def test_and_write
+ assert_desugars("(AndNode (ClassVariableReadNode) (ClassVariableWriteNode (CallNode)))", "@@foo &&= bar")
+ assert_not_desugared("Foo::Bar &&= baz", "Desugaring would execute Foo twice or need temporary variables")
+ assert_desugars("(AndNode (ConstantReadNode) (ConstantWriteNode (CallNode)))", "Foo &&= bar")
+ assert_desugars("(AndNode (GlobalVariableReadNode) (GlobalVariableWriteNode (CallNode)))", "$foo &&= bar")
+ assert_desugars("(AndNode (InstanceVariableReadNode) (InstanceVariableWriteNode (CallNode)))", "@foo &&= bar")
+ assert_desugars("(AndNode (LocalVariableReadNode) (LocalVariableWriteNode (CallNode)))", "foo &&= bar")
+ assert_desugars("(AndNode (LocalVariableReadNode) (LocalVariableWriteNode (CallNode)))", "foo = 1; foo &&= bar")
+ end
+
+ def test_or_write
+ assert_desugars("(IfNode (DefinedNode (ClassVariableReadNode)) (StatementsNode (ClassVariableReadNode)) (ElseNode (StatementsNode (ClassVariableWriteNode (CallNode)))))", "@@foo ||= bar")
+ assert_not_desugared("Foo::Bar ||= baz", "Desugaring would execute Foo twice or need temporary variables")
+ assert_desugars("(IfNode (DefinedNode (ConstantReadNode)) (StatementsNode (ConstantReadNode)) (ElseNode (StatementsNode (ConstantWriteNode (CallNode)))))", "Foo ||= bar")
+ assert_desugars("(IfNode (DefinedNode (GlobalVariableReadNode)) (StatementsNode (GlobalVariableReadNode)) (ElseNode (StatementsNode (GlobalVariableWriteNode (CallNode)))))", "$foo ||= bar")
+ assert_desugars("(OrNode (InstanceVariableReadNode) (InstanceVariableWriteNode (CallNode)))", "@foo ||= bar")
+ assert_desugars("(OrNode (LocalVariableReadNode) (LocalVariableWriteNode (CallNode)))", "foo ||= bar")
+ assert_desugars("(OrNode (LocalVariableReadNode) (LocalVariableWriteNode (CallNode)))", "foo = 1; foo ||= bar")
+ end
+
+ def test_operator_write
+ assert_desugars("(ClassVariableWriteNode (CallNode (ClassVariableReadNode) (ArgumentsNode (CallNode))))", "@@foo += bar")
+ assert_not_desugared("Foo::Bar += baz", "Desugaring would execute Foo twice or need temporary variables")
+ assert_desugars("(ConstantWriteNode (CallNode (ConstantReadNode) (ArgumentsNode (CallNode))))", "Foo += bar")
+ assert_desugars("(GlobalVariableWriteNode (CallNode (GlobalVariableReadNode) (ArgumentsNode (CallNode))))", "$foo += bar")
+ assert_desugars("(InstanceVariableWriteNode (CallNode (InstanceVariableReadNode) (ArgumentsNode (CallNode))))", "@foo += bar")
+ assert_desugars("(LocalVariableWriteNode (CallNode (LocalVariableReadNode) (ArgumentsNode (CallNode))))", "foo += bar")
+ assert_desugars("(LocalVariableWriteNode (CallNode (LocalVariableReadNode) (ArgumentsNode (CallNode))))", "foo = 1; foo += bar")
+ end
+
+ private
+
+ def ast_inspect(node)
+ parts = [node.class.name.split("::").last]
+
+ node.deconstruct_keys(nil).each do |_, value|
+ case value
+ when Node
+ parts << ast_inspect(value)
+ when Array
+ parts.concat(value.map { |element| ast_inspect(element) })
+ end
+ end
+
+ "(#{parts.join(" ")})"
+ end
+
+ # Ensure every node is only present once in the AST.
+ # If the same node is present twice it would most likely indicate it is executed twice, which is invalid semantically.
+ # This also acts as a sanity check that Node#child_nodes returns only nodes or nil (which caught a couple bugs).
+ def ensure_every_node_once_in_ast(node, all_nodes = {}.compare_by_identity)
+ if all_nodes.include?(node)
+ raise "#{node.inspect} is present multiple times in the desugared AST and likely executed multiple times"
+ else
+ all_nodes[node] = true
+ end
+ node.child_nodes.each do |child|
+ ensure_every_node_once_in_ast(child, all_nodes) unless child.nil?
+ end
+ end
+
+ def assert_desugars(expected, source)
+ ast = Prism.parse(source).value.accept(DesugarCompiler.new)
+ assert_equal expected, ast_inspect(ast.statements.body.last)
+
+ ensure_every_node_once_in_ast(ast)
+ end
+
+ def assert_not_desugared(source, reason)
+ ast = Prism.parse(source).value
+ assert_equal_nodes(ast, ast.accept(DesugarCompiler.new))
+ end
+ end
+end
diff --git a/test/prism/ruby/dispatcher_test.rb b/test/prism/ruby/dispatcher_test.rb
new file mode 100644
index 0000000000..83eb29e1f3
--- /dev/null
+++ b/test/prism/ruby/dispatcher_test.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class DispatcherTest < TestCase
+ class TestListener
+ attr_reader :events_received
+
+ def initialize
+ @events_received = []
+ end
+
+ def on_call_node_enter(node)
+ events_received << :on_call_node_enter
+ end
+
+ def on_call_node_leave(node)
+ events_received << :on_call_node_leave
+ end
+
+ def on_integer_node_enter(node)
+ events_received << :on_integer_node_enter
+ end
+ end
+
+ def test_dispatching_events
+ listener_manual = TestListener.new
+ listener_public = TestListener.new
+
+ dispatcher = Dispatcher.new
+ dispatcher.register(listener_manual, :on_call_node_enter, :on_call_node_leave, :on_integer_node_enter)
+ dispatcher.register_public_methods(listener_public)
+
+ root = Prism.parse(<<~RUBY).value
+ def foo
+ something(1, 2, 3)
+ end
+ RUBY
+
+ dispatcher.dispatch(root)
+
+ [listener_manual, listener_public].each do |listener|
+ assert_equal([:on_call_node_enter, :on_integer_node_enter, :on_integer_node_enter, :on_integer_node_enter, :on_call_node_leave], listener.events_received)
+ listener.events_received.clear
+ end
+
+ dispatcher.dispatch_once(root.statements.body.first.body.body.first)
+
+ [listener_manual, listener_public].each do |listener|
+ assert_equal([:on_call_node_enter, :on_call_node_leave], listener.events_received)
+ end
+ end
+ end
+end
diff --git a/test/prism/ruby/find_fixtures.rb b/test/prism/ruby/find_fixtures.rb
new file mode 100644
index 0000000000..c1bef0d0e6
--- /dev/null
+++ b/test/prism/ruby/find_fixtures.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+# Test fixtures for Prism.find. These must be in a separate file because
+# source_location returns the file path and Prism.find re-parses the file.
+
+module Prism
+ module FindFixtures
+ module Methods
+ def simple_method
+ 42
+ end
+
+ def method_with_params(a, b, c)
+ a + b + c
+ end
+
+ def method_with_block(&block)
+ block.call
+ end
+
+ def self.singleton_method_fixture
+ :singleton
+ end
+
+ def été
+ :utf8
+ end
+
+ def inline_method; :inline; end
+ end
+
+ module Procs
+ SIMPLE_PROC = proc { 42 }
+ SIMPLE_LAMBDA = ->(x) { x * 2 }
+ MULTI_LINE_LAMBDA = lambda do |x|
+ x + 1
+ end
+ DO_BLOCK_PROC = proc do |x|
+ x - 1
+ end
+ end
+
+ module DefineMethod
+ define_method(:dynamic) { |x| x + 1 }
+ end
+
+ module ForLoop
+ for_proc = nil
+ o = Object.new
+ def o.each(&block) = block.call(block)
+ for for_proc in o; end
+ FOR_PROC = for_proc
+ end
+
+ module MultipleOnLine
+ def self.first; end; def self.second; end
+ end
+
+ module Errors
+ def self.divide(a, b)
+ a / b
+ end
+
+ def self.call_undefined
+ undefined_method_call
+ end
+ end
+ end
+end
diff --git a/test/prism/ruby/find_test.rb b/test/prism/ruby/find_test.rb
new file mode 100644
index 0000000000..5b59113d30
--- /dev/null
+++ b/test/prism/ruby/find_test.rb
@@ -0,0 +1,242 @@
+# frozen_string_literal: true
+
+return if RUBY_ENGINE == "ruby" && RUBY_VERSION < "3.4"
+return if defined?(RubyVM::InstructionSequence) && RubyVM::InstructionSequence.compile("").to_a[4][:parser] != :prism
+
+require_relative "../test_helper"
+require_relative "find_fixtures"
+
+module Prism
+ class FindTest < TestCase
+ Fixtures = FindFixtures
+ FIXTURES_PATH = File.expand_path("find_fixtures.rb", __dir__)
+
+ # === Method / UnboundMethod tests ===
+
+ def test_simple_method
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:simple_method)), :simple_method
+ end
+
+ def test_method_with_params
+ node = Prism.find(Fixtures::Methods.instance_method(:method_with_params))
+ assert_def_node node, :method_with_params
+ assert_equal 3, node.parameters.requireds.length
+ end
+
+ def test_method_with_block_param
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:method_with_block)), :method_with_block
+ end
+
+ def test_singleton_method
+ assert_def_node Prism.find(Fixtures::Methods.method(:singleton_method_fixture)), :singleton_method_fixture
+ end
+
+ def test_utf8_method_name
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:été)), :été
+ end
+
+ def test_inline_method
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:inline_method)), :inline_method
+ end
+
+ def test_bound_method
+ obj = Object.new
+ obj.extend(Fixtures::Methods)
+ assert_def_node Prism.find(obj.method(:simple_method)), :simple_method
+ end
+
+ # === Proc / Lambda tests ===
+
+ def test_simple_proc
+ assert_not_nil Prism.find(Fixtures::Procs::SIMPLE_PROC)
+ end
+
+ def test_simple_lambda
+ assert_not_nil Prism.find(Fixtures::Procs::SIMPLE_LAMBDA)
+ end
+
+ def test_multi_line_lambda
+ assert_not_nil Prism.find(Fixtures::Procs::MULTI_LINE_LAMBDA)
+ end
+
+ def test_do_block_proc
+ assert_not_nil Prism.find(Fixtures::Procs::DO_BLOCK_PROC)
+ end
+
+ # === define_method tests ===
+
+ def test_define_method
+ assert_not_nil Prism.find(Fixtures::DefineMethod.instance_method(:dynamic))
+ end
+
+ def test_define_method_bound
+ obj = Object.new
+ obj.extend(Fixtures::DefineMethod)
+ assert_not_nil Prism.find(obj.method(:dynamic))
+ end
+
+ # === for loop test ===
+
+ def test_for_loop_proc
+ node = Prism.find(Fixtures::ForLoop::FOR_PROC)
+ assert_instance_of ForNode, node
+ end
+
+ # === Thread::Backtrace::Location tests ===
+
+ def test_backtrace_location_zero_division
+ location = zero_division_location
+ assert_not_nil location, "could not find backtrace location in fixtures file"
+ assert_not_nil Prism.find(location)
+ end
+
+ def test_backtrace_location_name_error
+ location = begin
+ Fixtures::Errors.call_undefined
+ rescue NameError => e
+ fixture_backtrace_location(e)
+ end
+
+ assert_not_nil location, "could not find backtrace location in fixtures file"
+ assert_not_nil Prism.find(location)
+ end
+
+ def test_backtrace_location_from_caller
+ # caller_locations returns locations for the current call stack
+ location = caller_locations(0, 1).first
+ node = Prism.find(location)
+ assert_not_nil node
+ end
+
+ def test_backtrace_location_eval_returns_nil
+ location = begin
+ eval("raise 'eval error'")
+ rescue RuntimeError => e
+ e.backtrace_locations.find { |loc| loc.path == "(eval)" || loc.label&.include?("eval") }
+ end
+
+ # eval locations have no file on disk
+ assert_nil Prism.find(location) if location
+ end
+
+ # === Edge cases ===
+
+ def test_nil_source_location
+ # Built-in methods have nil source_location
+ assert_nil Prism.find(method(:puts))
+ end
+
+ def test_argument_error_on_wrong_type
+ assert_raise(ArgumentError) { Prism.find("not a callable") }
+ assert_raise(ArgumentError) { Prism.find(42) }
+ assert_raise(ArgumentError) { Prism.find(nil) }
+ end
+
+ def test_eval_returns_nil
+ # eval'd code has no file on disk
+ m = eval("proc { 1 }")
+ assert_nil Prism.find(m)
+ end
+
+ def test_multiple_methods_on_same_line
+ assert_def_node Prism.find(Fixtures::MultipleOnLine.method(:first)), :first
+ assert_def_node Prism.find(Fixtures::MultipleOnLine.method(:second)), :second
+ end
+
+ # === Fallback (line-based) tests via rubyvm: false ===
+
+ def test_fallback_simple_method
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:simple_method), rubyvm: false), :simple_method
+ end
+
+ def test_fallback_singleton_method
+ assert_def_node Prism.find(Fixtures::Methods.method(:singleton_method_fixture), rubyvm: false), :singleton_method_fixture
+ end
+
+ def test_fallback_lambda
+ node = Prism.find(Fixtures::Procs::SIMPLE_LAMBDA, rubyvm: false)
+ assert_instance_of LambdaNode, node
+ end
+
+ def test_fallback_proc
+ node = Prism.find(Fixtures::Procs::SIMPLE_PROC, rubyvm: false)
+ assert_instance_of CallNode, node
+ assert node.block.is_a?(BlockNode)
+ end
+
+ def test_fallback_define_method
+ node = Prism.find(Fixtures::DefineMethod.instance_method(:dynamic), rubyvm: false)
+ assert_instance_of CallNode, node
+ assert node.block.is_a?(BlockNode)
+ end
+
+ def test_fallback_for_loop
+ node = Prism.find(Fixtures::ForLoop::FOR_PROC, rubyvm: false)
+ assert_instance_of ForNode, node
+ end
+
+ def test_fallback_backtrace_location
+ location = zero_division_location
+ assert_not_nil location
+ node = Prism.find(location, rubyvm: false)
+ assert_not_nil node
+ assert_equal location.lineno, node.location.start_line
+ end
+
+ # === Node identity with node_id (CRuby only) ===
+
+ if defined?(RubyVM::InstructionSequence)
+ def test_node_id_matches_iseq
+ m = Fixtures::Methods.instance_method(:simple_method)
+ node = Prism.find(m)
+ assert_equal node_id_of(m), node.node_id
+ end
+
+ def test_node_id_for_lambda
+ node = Prism.find(Fixtures::Procs::SIMPLE_LAMBDA)
+ assert_equal node_id_of(Fixtures::Procs::SIMPLE_LAMBDA), node.node_id
+ end
+
+ def test_node_id_for_proc
+ node = Prism.find(Fixtures::Procs::SIMPLE_PROC)
+ assert_equal node_id_of(Fixtures::Procs::SIMPLE_PROC), node.node_id
+ end
+
+ def test_node_id_for_define_method
+ m = Fixtures::DefineMethod.instance_method(:dynamic)
+ node = Prism.find(m)
+ assert_equal node_id_of(m), node.node_id
+ end
+
+ def test_node_id_for_backtrace_location
+ location = zero_division_location
+ assert_not_nil location
+ expected_node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location)
+
+ node = Prism.find(location)
+ assert_equal expected_node_id, node.node_id
+ end
+ end
+
+ private
+
+ def assert_def_node(node, expected_name)
+ assert_instance_of DefNode, node
+ assert_equal expected_name, node.name
+ end
+
+ def fixture_backtrace_location(exception)
+ exception.backtrace_locations.find { |loc| loc.path == FIXTURES_PATH }
+ end
+
+ def zero_division_location
+ Fixtures::Errors.divide(1, 0)
+ rescue ZeroDivisionError => e
+ fixture_backtrace_location(e)
+ end
+
+ def node_id_of(callable)
+ RubyVM::InstructionSequence.of(callable).to_a[4][:node_id]
+ end
+ end
+end
diff --git a/test/prism/ruby/location_test.rb b/test/prism/ruby/location_test.rb
new file mode 100644
index 0000000000..12c4258cde
--- /dev/null
+++ b/test/prism/ruby/location_test.rb
@@ -0,0 +1,254 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class LocationTest < TestCase
+ def test_join
+ call = Prism.parse_statement("1234 + 567")
+ receiver = call.receiver
+ argument = call.arguments.arguments.first
+
+ joined = receiver.location.join(argument.location)
+ assert_equal 0, joined.start_offset
+ assert_equal 10, joined.length
+
+ e = assert_raise(RuntimeError) do
+ argument.location.join(receiver.location)
+ end
+ assert_equal "Incompatible locations", e.message
+
+ other_argument = Prism.parse_statement("1234 + 567").arguments.arguments.first
+
+ e = assert_raise(RuntimeError) do
+ other_argument.location.join(receiver.location)
+ end
+ assert_equal "Incompatible sources", e.message
+
+ e = assert_raise(RuntimeError) do
+ receiver.location.join(other_argument.location)
+ end
+ assert_equal "Incompatible sources", e.message
+ end
+
+ def test_character_offsets
+ program = Prism.parse("😀 + 😀\n😍 ||= 😍").value
+
+ # first 😀
+ location = program.statements.body.first.receiver.location
+ assert_equal 0, location.start_character_offset
+ assert_equal 1, location.end_character_offset
+ assert_equal 0, location.start_character_column
+ assert_equal 1, location.end_character_column
+
+ # second 😀
+ location = program.statements.body.first.arguments.arguments.first.location
+ assert_equal 4, location.start_character_offset
+ assert_equal 5, location.end_character_offset
+ assert_equal 4, location.start_character_column
+ assert_equal 5, location.end_character_column
+
+ # first 😍
+ location = program.statements.body.last.name_loc
+ assert_equal 6, location.start_character_offset
+ assert_equal 7, location.end_character_offset
+ assert_equal 0, location.start_character_column
+ assert_equal 1, location.end_character_column
+
+ # second 😍
+ location = program.statements.body.last.value.location
+ assert_equal 12, location.start_character_offset
+ assert_equal 13, location.end_character_offset
+ assert_equal 6, location.start_character_column
+ assert_equal 7, location.end_character_column
+ end
+
+ def test_code_units
+ program = Prism.parse("😀 + 😀\n😍 ||= 😍").value
+
+ # first 😀
+ location = program.statements.body.first.receiver.location
+
+ assert_equal 0, location.start_code_units_offset(Encoding::UTF_8)
+ assert_equal 0, location.start_code_units_offset(Encoding::UTF_16LE)
+ assert_equal 0, location.start_code_units_offset(Encoding::UTF_32LE)
+
+ assert_equal 4, location.end_code_units_offset(Encoding::UTF_8)
+ assert_equal 2, location.end_code_units_offset(Encoding::UTF_16LE)
+ assert_equal 1, location.end_code_units_offset(Encoding::UTF_32LE)
+
+ assert_equal 0, location.start_code_units_column(Encoding::UTF_8)
+ assert_equal 0, location.start_code_units_column(Encoding::UTF_16LE)
+ assert_equal 0, location.start_code_units_column(Encoding::UTF_32LE)
+
+ assert_equal 4, location.end_code_units_column(Encoding::UTF_8)
+ assert_equal 2, location.end_code_units_column(Encoding::UTF_16LE)
+ assert_equal 1, location.end_code_units_column(Encoding::UTF_32LE)
+
+ # second 😀
+ location = program.statements.body.first.arguments.arguments.first.location
+
+ assert_equal 7, location.start_code_units_offset(Encoding::UTF_8)
+ assert_equal 5, location.start_code_units_offset(Encoding::UTF_16LE)
+ assert_equal 4, location.start_code_units_offset(Encoding::UTF_32LE)
+
+ assert_equal 11, location.end_code_units_offset(Encoding::UTF_8)
+ assert_equal 7, location.end_code_units_offset(Encoding::UTF_16LE)
+ assert_equal 5, location.end_code_units_offset(Encoding::UTF_32LE)
+
+ assert_equal 7, location.start_code_units_column(Encoding::UTF_8)
+ assert_equal 5, location.start_code_units_column(Encoding::UTF_16LE)
+ assert_equal 4, location.start_code_units_column(Encoding::UTF_32LE)
+
+ assert_equal 11, location.end_code_units_column(Encoding::UTF_8)
+ assert_equal 7, location.end_code_units_column(Encoding::UTF_16LE)
+ assert_equal 5, location.end_code_units_column(Encoding::UTF_32LE)
+
+ # first 😍
+ location = program.statements.body.last.name_loc
+
+ assert_equal 12, location.start_code_units_offset(Encoding::UTF_8)
+ assert_equal 8, location.start_code_units_offset(Encoding::UTF_16LE)
+ assert_equal 6, location.start_code_units_offset(Encoding::UTF_32LE)
+
+ assert_equal 16, location.end_code_units_offset(Encoding::UTF_8)
+ assert_equal 10, location.end_code_units_offset(Encoding::UTF_16LE)
+ assert_equal 7, location.end_code_units_offset(Encoding::UTF_32LE)
+
+ assert_equal 0, location.start_code_units_column(Encoding::UTF_8)
+ assert_equal 0, location.start_code_units_column(Encoding::UTF_16LE)
+ assert_equal 0, location.start_code_units_column(Encoding::UTF_32LE)
+
+ assert_equal 4, location.end_code_units_column(Encoding::UTF_8)
+ assert_equal 2, location.end_code_units_column(Encoding::UTF_16LE)
+ assert_equal 1, location.end_code_units_column(Encoding::UTF_32LE)
+
+ # second 😍
+ location = program.statements.body.last.value.location
+
+ assert_equal 21, location.start_code_units_offset(Encoding::UTF_8)
+ assert_equal 15, location.start_code_units_offset(Encoding::UTF_16LE)
+ assert_equal 12, location.start_code_units_offset(Encoding::UTF_32LE)
+
+ assert_equal 25, location.end_code_units_offset(Encoding::UTF_8)
+ assert_equal 17, location.end_code_units_offset(Encoding::UTF_16LE)
+ assert_equal 13, location.end_code_units_offset(Encoding::UTF_32LE)
+
+ assert_equal 9, location.start_code_units_column(Encoding::UTF_8)
+ assert_equal 7, location.start_code_units_column(Encoding::UTF_16LE)
+ assert_equal 6, location.start_code_units_column(Encoding::UTF_32LE)
+
+ assert_equal 13, location.end_code_units_column(Encoding::UTF_8)
+ assert_equal 9, location.end_code_units_column(Encoding::UTF_16LE)
+ assert_equal 7, location.end_code_units_column(Encoding::UTF_32LE)
+ end
+
+ def test_cached_code_units
+ result = Prism.parse("😀 + 😀\n😍 ||= 😍")
+
+ utf8_cache = result.code_units_cache(Encoding::UTF_8)
+ utf16_cache = result.code_units_cache(Encoding::UTF_16LE)
+ utf32_cache = result.code_units_cache(Encoding::UTF_32LE)
+
+ # first 😀
+ location = result.value.statements.body.first.receiver.location
+
+ assert_equal 0, location.cached_start_code_units_offset(utf8_cache)
+ assert_equal 0, location.cached_start_code_units_offset(utf16_cache)
+ assert_equal 0, location.cached_start_code_units_offset(utf32_cache)
+
+ assert_equal 4, location.cached_end_code_units_offset(utf8_cache)
+ assert_equal 2, location.cached_end_code_units_offset(utf16_cache)
+ assert_equal 1, location.cached_end_code_units_offset(utf32_cache)
+
+ assert_equal 0, location.cached_start_code_units_column(utf8_cache)
+ assert_equal 0, location.cached_start_code_units_column(utf16_cache)
+ assert_equal 0, location.cached_start_code_units_column(utf32_cache)
+
+ assert_equal 4, location.cached_end_code_units_column(utf8_cache)
+ assert_equal 2, location.cached_end_code_units_column(utf16_cache)
+ assert_equal 1, location.cached_end_code_units_column(utf32_cache)
+
+ # second 😀
+ location = result.value.statements.body.first.arguments.arguments.first.location
+
+ assert_equal 7, location.cached_start_code_units_offset(utf8_cache)
+ assert_equal 5, location.cached_start_code_units_offset(utf16_cache)
+ assert_equal 4, location.cached_start_code_units_offset(utf32_cache)
+
+ assert_equal 11, location.cached_end_code_units_offset(utf8_cache)
+ assert_equal 7, location.cached_end_code_units_offset(utf16_cache)
+ assert_equal 5, location.cached_end_code_units_offset(utf32_cache)
+
+ assert_equal 7, location.cached_start_code_units_column(utf8_cache)
+ assert_equal 5, location.cached_start_code_units_column(utf16_cache)
+ assert_equal 4, location.cached_start_code_units_column(utf32_cache)
+
+ assert_equal 11, location.cached_end_code_units_column(utf8_cache)
+ assert_equal 7, location.cached_end_code_units_column(utf16_cache)
+ assert_equal 5, location.cached_end_code_units_column(utf32_cache)
+ end
+
+ def test_code_units_binary_valid_utf8
+ program = Prism.parse(<<~RUBY).value
+ # -*- encoding: binary -*-
+
+ 😀 + 😀
+ RUBY
+
+ receiver = program.statements.body.first.receiver
+ assert_equal "😀".b.to_sym, receiver.name
+
+ location = receiver.location
+ assert_equal 4, location.end_code_units_column(Encoding::UTF_8)
+ assert_equal 2, location.end_code_units_column(Encoding::UTF_16LE)
+ assert_equal 1, location.end_code_units_column(Encoding::UTF_32LE)
+ end
+
+ def test_code_units_binary_invalid_utf8
+ program = Prism.parse(<<~RUBY).value
+ # -*- encoding: binary -*-
+
+ \x90 + \x90
+ RUBY
+
+ receiver = program.statements.body.first.receiver
+ assert_equal "\x90".b.to_sym, receiver.name
+
+ location = receiver.location
+ assert_equal 1, location.end_code_units_column(Encoding::UTF_8)
+ assert_equal 1, location.end_code_units_column(Encoding::UTF_16LE)
+ assert_equal 1, location.end_code_units_column(Encoding::UTF_32LE)
+ end
+
+ def test_chop
+ location = Prism.parse("foo").value.location
+
+ assert_equal "fo", location.chop.slice
+ assert_equal "", location.chop.chop.chop.slice
+
+ # Check that we don't go negative.
+ 10.times { location = location.chop }
+ assert_equal "", location.slice
+ end
+
+ def test_slice_lines
+ method = Prism.parse_statement("\nprivate def foo\nend\n").arguments.arguments.first
+
+ assert_equal "private def foo\nend\n", method.slice_lines
+ end
+
+ def test_adjoin
+ program = Prism.parse("foo.bar = 1").value
+
+ location = program.statements.body.first.message_loc
+ adjoined = location.adjoin("=")
+
+ assert_kind_of Location, adjoined
+ refute_equal location, adjoined
+
+ assert_equal 4, adjoined.start_offset
+ assert_equal 9, adjoined.end_offset
+ end
+ end
+end
diff --git a/test/prism/ruby/parameters_signature_test.rb b/test/prism/ruby/parameters_signature_test.rb
new file mode 100644
index 0000000000..1ca2b144a9
--- /dev/null
+++ b/test/prism/ruby/parameters_signature_test.rb
@@ -0,0 +1,105 @@
+# frozen_string_literal: true
+
+return if RUBY_VERSION < "3.2"
+
+require_relative "../test_helper"
+
+module Prism
+ class ParametersSignatureTest < TestCase
+ def test_req
+ assert_parameters([[:req, :a]], "a")
+ end
+
+ def test_req_destructure
+ assert_parameters([[:req]], "(a, b)")
+ end
+
+ def test_opt
+ assert_parameters([[:opt, :a]], "a = 1")
+ end
+
+ def test_rest
+ assert_parameters([[:rest, :a]], "*a")
+ end
+
+ def test_rest_anonymous
+ assert_parameters([[:rest, :*]], "*")
+ end
+
+ def test_post
+ assert_parameters([[:rest, :a], [:req, :b]], "*a, b")
+ end
+
+ def test_post_destructure
+ assert_parameters([[:rest, :a], [:req]], "*a, (b, c)")
+ end
+
+ def test_keyreq
+ assert_parameters([[:keyreq, :a]], "a:")
+ end
+
+ def test_key
+ assert_parameters([[:key, :a]], "a: 1")
+ end
+
+ def test_keyrest
+ assert_parameters([[:keyrest, :a]], "**a")
+ end
+
+ def test_nokey
+ assert_parameters([[:nokey]], "**nil")
+ end
+
+ def test_noblock
+ # FIXME: `compare: RUBY_VERSION >= "4.1"` once builds are available
+ assert_parameters([[:noblock]], "&nil", compare: false)
+ end
+
+ def test_keyrest_anonymous
+ assert_parameters([[:keyrest, :**]], "**")
+ end
+
+ if RUBY_ENGINE == "ruby"
+ def test_key_ordering
+ assert_parameters([[:keyreq, :a], [:keyreq, :b], [:key, :c], [:key, :d]], "a:, c: 1, b:, d: 2")
+ end
+ end
+
+ def test_block
+ assert_parameters([[:block, :a]], "&a")
+ end
+
+ def test_block_anonymous
+ assert_parameters([[:block, :&]], "&")
+ end
+
+ def test_forwarding
+ assert_parameters([[:rest, :*], [:keyrest, :**], [:block, :&]], "...")
+ end
+
+ def test_invalid_syntax
+ e = assert_raise(RuntimeError) do
+ Prism.parse_statement("def f(**nil, ...); end").parameters.signature
+ end
+ assert_equal("Invalid syntax", e.message)
+ end
+
+ private
+
+ def assert_parameters(expected, source, compare: true)
+ # Compare against our expectation.
+ assert_equal(expected, signature(source))
+
+ return unless compare
+ # Compare against Ruby's expectation.
+ object = Object.new
+ eval("def object.m(#{source}); end")
+ assert_equal(expected, object.method(:m).parameters)
+ end
+
+ def signature(source)
+ program = Prism.parse("def m(#{source}); end").value
+ program.statements.body.first.parameters.signature
+ end
+ end
+end
diff --git a/test/prism/ruby/parser_test.rb b/test/prism/ruby/parser_test.rb
new file mode 100644
index 0000000000..ad9fa0c92c
--- /dev/null
+++ b/test/prism/ruby/parser_test.rb
@@ -0,0 +1,323 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+begin
+ verbose, $VERBOSE = $VERBOSE, nil
+ require "parser/ruby33"
+rescue LoadError
+ # In CRuby's CI, we're not going to test against the parser gem because we
+ # don't want to have to install it. So in this case we'll just skip this test.
+ return
+ensure
+ $VERBOSE = verbose
+end
+
+# First, opt in to every AST feature.
+Parser::Builders::Default.modernize
+Prism::Translation::Parser::Builder.modernize
+
+# The parser gem rejects some strings that would most likely lead to errors
+# in consumers due to encoding problems. RuboCop however monkey-patches this
+# method out in order to accept such code.
+# https://github.com/whitequark/parser/blob/v3.3.6.0/lib/parser/builders/default.rb#L2289-L2295
+Parser::Builders::Default.prepend(
+ Module.new {
+ def string_value(token)
+ value(token)
+ end
+ }
+)
+
+# Modify the source map == check so that it doesn't check against the node
+# itself so we don't get into a recursive loop.
+Parser::Source::Map.prepend(
+ Module.new {
+ def ==(other)
+ self.class == other.class &&
+ (instance_variables - %i[@node]).map do |ivar|
+ instance_variable_get(ivar) == other.instance_variable_get(ivar)
+ end.reduce(:&)
+ end
+ }
+)
+
+# Next, ensure that we're comparing the nodes and also comparing the source
+# ranges so that we're getting all of the necessary information.
+Parser::AST::Node.prepend(
+ Module.new {
+ def ==(other)
+ super && (location == other.location)
+ end
+ }
+)
+
+module Prism
+ class ParserTest < TestCase
+ # These files contain code with valid syntax that can't be parsed.
+ skip_syntax_error = [
+ # alias/undef with %s(abc) symbol literal
+ "alias.txt",
+ "seattlerb/bug_215.txt",
+
+ # %Q with newline delimiter and heredoc interpolation
+ "heredoc_percent_q_newline_delimiter.txt",
+
+ # 1.. && 2
+ "ranges.txt",
+
+ # https://bugs.ruby-lang.org/issues/21168#note-5
+ "command_method_call_2.txt",
+ ]
+
+ # These files contain code that is being parsed incorrectly by the parser
+ # gem, and therefore we don't want to compare against our translation.
+ skip_incorrect = [
+ # https://github.com/whitequark/parser/issues/1017
+ "spanning_heredoc.txt",
+ "spanning_heredoc_newlines.txt",
+
+ # https://github.com/whitequark/parser/issues/1021
+ "seattlerb/heredoc_nested.txt",
+
+ # https://github.com/whitequark/parser/issues/1016
+ "whitequark/unary_num_pow_precedence.txt",
+
+ # https://github.com/whitequark/parser/issues/950
+ "whitequark/dedenting_interpolating_heredoc_fake_line_continuation.txt",
+
+ # Contains an escaped multibyte character. This is supposed to drop to backslash
+ "seattlerb/regexp_escape_extended.txt",
+
+ # https://github.com/whitequark/parser/issues/1020
+ # These contain consecutive \r characters, followed by \n. Prism only receives
+ # the already modified source buffer which dropped one \r but must know the
+ # original code to parse it correctly.
+ "seattlerb/heredoc_with_extra_carriage_returns_windows.txt",
+ "seattlerb/heredoc_with_only_carriage_returns_windows.txt",
+ "seattlerb/heredoc_with_only_carriage_returns.txt",
+
+ # https://github.com/whitequark/parser/issues/1026
+ # Regex with \c escape
+ "unescaping.txt",
+ "seattlerb/regexp_esc_C_slash.txt",
+
+ # https://github.com/whitequark/parser/issues/1084
+ "unary_method_calls.txt",
+ ]
+
+ # These files are failing to translate their lexer output into the lexer
+ # output expected by the parser gem, so we'll skip them for now.
+ skip_tokens = [
+ "dash_heredocs.txt",
+ "embdoc_no_newline_at_end.txt",
+ "methods.txt",
+ "seattlerb/bug169.txt",
+ "seattlerb/case_in.txt",
+ "seattlerb/difficult4__leading_dots2.txt",
+ "seattlerb/difficult6__7.txt",
+ "seattlerb/difficult6__8.txt",
+ "seattlerb/heredoc_unicode.txt",
+ "seattlerb/parse_line_heredoc.txt",
+ "seattlerb/pct_w_heredoc_interp_nested.txt",
+ "seattlerb/required_kwarg_no_value.txt",
+ "seattlerb/TestRubyParserShared.txt",
+ "unparser/corpus/literal/assignment.txt",
+ "unparser/corpus/literal/literal.txt",
+ "whitequark/args.txt",
+ "whitequark/beginless_erange_after_newline.txt",
+ "whitequark/beginless_irange_after_newline.txt",
+ "whitequark/forward_arg_with_open_args.txt",
+ "whitequark/kwarg_no_paren.txt",
+ "whitequark/lbrace_arg_after_command_args.txt",
+ "whitequark/multiple_pattern_matches.txt",
+ "whitequark/newline_in_hash_argument.txt",
+ "whitequark/pattern_matching_expr_in_paren.txt",
+ "whitequark/pattern_matching_hash.txt",
+ "whitequark/ruby_bug_14690.txt",
+ "whitequark/ruby_bug_9669.txt",
+ "whitequark/space_args_arg_block.txt",
+ "whitequark/space_args_block.txt"
+ ]
+
+ Fixture.each_for_version(except: skip_syntax_error, version: "3.3") do |fixture|
+ define_method(fixture.test_name) do
+ assert_equal_parses(
+ fixture,
+ compare_asts: !skip_incorrect.include?(fixture.path),
+ compare_tokens: !skip_tokens.include?(fixture.path),
+ compare_comments: fixture.path != "embdoc_no_newline_at_end.txt"
+ )
+ end
+ end
+
+ def test_non_prism_builder_class_deprecated
+ warnings = capture_warnings { Prism::Translation::Parser33.new(Parser::Builders::Default.new) }
+
+ assert_include(warnings, "#{__FILE__}:#{__LINE__ - 2}")
+ assert_include(warnings, "is not a `Prism::Translation::Parser::Builder` subclass")
+
+ warnings = capture_warnings { Prism::Translation::Parser33.new }
+ assert_empty(warnings)
+ end
+
+ if RUBY_VERSION >= "3.3"
+ def test_current_parser_for_current_ruby
+ major, minor = CURRENT_MAJOR_MINOR.split(".")
+ # Let's just hope there never is a Ruby 3.10 or similar
+ expected = major.to_i * 10 + minor.to_i
+ assert_equal(expected, Translation::ParserCurrent.new.version)
+ end
+ end
+
+ def test_invalid_syntax
+ code = <<~RUBY
+ foo do
+ case bar
+ when
+ end
+ end
+ RUBY
+ buffer = Parser::Source::Buffer.new("(string)")
+ buffer.source = code
+
+ parser = Prism::Translation::Parser33.new
+ parser.diagnostics.all_errors_are_fatal = true
+ assert_raise(Parser::SyntaxError) { parser.tokenize(buffer) }
+ end
+
+ def test_it_block_parameter_syntax
+ assert_new_syntax("3.4/it.txt", Prism::Translation::Parser34) do
+ s(:begin,
+ s(:itblock,
+ s(:send, nil, :x), :it,
+ s(:lvar, :it)),
+ s(:itblock,
+ s(:lambda), :it,
+ s(:lvar, :it)))
+ end
+ end
+
+ def test_nil_block_parameter_syntax
+ assert_new_syntax("4.1/noblock.txt", Prism::Translation::Parser41) do
+ s(:begin,
+ s(:def, :foo,
+ s(:args,
+ s(:blocknilarg)), nil),
+ s(:block,
+ s(:lambda),
+ s(:args,
+ s(:blocknilarg)), nil))
+ end
+ end
+
+ private
+
+ def assert_equal_parses(fixture, compare_asts: true, compare_tokens: true, compare_comments: true)
+ buffer = Parser::Source::Buffer.new(fixture.path, 1)
+ buffer.source = fixture.read
+
+ parser = Parser::Ruby33.new
+ parser.diagnostics.consumer = ->(*) {}
+ parser.diagnostics.all_errors_are_fatal = true
+
+ expected_ast, expected_comments, expected_tokens =
+ ignore_warnings { parser.tokenize(buffer) }
+
+ actual_ast, actual_comments, actual_tokens =
+ ignore_warnings { Prism::Translation::Parser33.new.tokenize(buffer) }
+
+ if expected_ast == actual_ast
+ if !compare_asts && !Fixture.custom_base_path?
+ puts "#{fixture.path} is now passing"
+ end
+
+ assert_equal expected_ast, actual_ast, -> { assert_equal_asts_message(expected_ast, actual_ast) }
+
+ begin
+ assert_equal_tokens(expected_tokens, actual_tokens)
+ rescue Test::Unit::AssertionFailedError
+ raise if compare_tokens
+ else
+ puts "#{fixture.path} is now passing" if !compare_tokens && !Fixture.custom_base_path?
+ end
+
+ assert_equal_comments(expected_comments, actual_comments) if compare_comments
+ elsif compare_asts
+ assert_equal expected_ast, actual_ast, -> { assert_equal_asts_message(expected_ast, actual_ast) }
+ end
+ end
+
+ def assert_equal_asts_message(expected_ast, actual_ast)
+ queue = [[expected_ast, actual_ast]]
+
+ while (left, right = queue.shift)
+ if left.type != right.type
+ return "expected: #{left.type}\nactual: #{right.type}"
+ end
+
+ if left.location != right.location
+ return "expected:\n#{left.inspect}\n#{left.location.inspect}\nactual:\n#{right.inspect}\n#{right.location.inspect}"
+ end
+
+ if left.type == :str && left.children[0] != right.children[0]
+ return "expected: #{left.inspect}\nactual: #{right.inspect}"
+ end
+
+ left.children.zip(right.children).each do |left_child, right_child|
+ queue << [left_child, right_child] if left_child.is_a?(Parser::AST::Node)
+ end
+ end
+
+ "expected: #{expected_ast.inspect}\nactual: #{actual_ast.inspect}"
+ end
+
+ def assert_equal_tokens(expected_tokens, actual_tokens)
+ if expected_tokens != actual_tokens
+ index = 0
+ max_index = [expected_tokens, actual_tokens].map(&:size).max
+
+ while index <= max_index
+ expected_token = expected_tokens.fetch(index, [])
+ actual_token = actual_tokens.fetch(index, [])
+
+ index += 1
+
+ # There are a lot of tokens that have very specific meaning according
+ # to the context of the parser. We don't expose that information in
+ # prism, so we need to normalize these tokens a bit.
+ if expected_token[0] == :kDO_BLOCK && actual_token[0] == :kDO
+ actual_token[0] = expected_token[0]
+ end
+
+ # Now we can assert that the tokens are actually equal.
+ assert_equal expected_token, actual_token, -> {
+ "expected: #{expected_token.inspect}\n" \
+ "actual: #{actual_token.inspect}"
+ }
+ end
+ end
+ end
+
+ def assert_equal_comments(expected_comments, actual_comments)
+ assert_equal expected_comments, actual_comments, -> {
+ "expected: #{expected_comments.inspect}\n" \
+ "actual: #{actual_comments.inspect}"
+ }
+ end
+
+ def assert_new_syntax(path, parser, &sexp)
+ fixture_path = Pathname(__dir__).join("../../../test/prism/fixtures", path)
+
+ buffer = Parser::Source::Buffer.new(fixture_path)
+ buffer.source = fixture_path.read
+ actual_ast = parser.new.tokenize(buffer)[0]
+
+ assert_equal(parse_sexp(&sexp), actual_ast.to_sexp)
+ end
+
+ def parse_sexp(&block)
+ Class.new { extend AST::Sexp }.instance_eval(&block).to_sexp
+ end
+ end
+end
diff --git a/test/prism/ruby/pattern_test.rb b/test/prism/ruby/pattern_test.rb
new file mode 100644
index 0000000000..23f512fc1c
--- /dev/null
+++ b/test/prism/ruby/pattern_test.rb
@@ -0,0 +1,132 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class PatternTest < TestCase
+ def test_invalid_syntax
+ assert_raise(Pattern::CompilationError) { scan("", "<>") }
+ end
+
+ def test_invalid_constant
+ assert_raise(Pattern::CompilationError) { scan("", "Foo") }
+ end
+
+ def test_invalid_nested_constant
+ assert_raise(Pattern::CompilationError) { scan("", "Foo::Bar") }
+ end
+
+ def test_regexp_with_interpolation
+ assert_raise(Pattern::CompilationError) { scan("", "/\#{foo}/") }
+ end
+
+ def test_string_with_interpolation
+ assert_raise(Pattern::CompilationError) { scan("", '"#{foo}"') }
+ end
+
+ def test_symbol_with_interpolation
+ assert_raise(Pattern::CompilationError) { scan("", ":\"\#{foo}\"") }
+ end
+
+ def test_invalid_node
+ assert_raise(Pattern::CompilationError) { scan("", "IntegerNode[^foo]") }
+ end
+
+ def test_self
+ assert_raise(Pattern::CompilationError) { scan("", "self") }
+ end
+
+ def test_array_pattern_no_constant
+ results = scan("1 + 2", "[IntegerNode]")
+
+ assert_equal 1, results.length
+ end
+
+ def test_array_pattern
+ results = scan("1 + 2", "CallNode[name: :+, receiver: IntegerNode, arguments: [IntegerNode]]")
+
+ assert_equal 1, results.length
+ end
+
+ def test_alternation_pattern
+ results = scan("Foo + Bar + 1", "ConstantReadNode | IntegerNode")
+
+ assert_equal 3, results.length
+ assert_equal 1, results.grep(IntegerNode).first.value
+ end
+
+ def test_constant_read_node
+ results = scan("Foo + Bar + Baz", "ConstantReadNode")
+
+ assert_equal 3, results.length
+ assert_equal %w[Bar Baz Foo], results.map(&:slice).sort
+ end
+
+ def test_object_const
+ results = scan("1 + 2 + 3", "IntegerNode[]")
+
+ assert_equal 3, results.length
+ end
+
+ def test_constant_path
+ results = scan("Foo + Bar + Baz", "Prism::ConstantReadNode")
+
+ assert_equal 3, results.length
+ end
+
+ def test_hash_pattern_no_constant
+ results = scan("Foo + Bar + Baz", "{ name: :+ }")
+
+ assert_equal 2, results.length
+ end
+
+ def test_hash_pattern_regexp
+ results = scan("Foo + Bar + Baz", "{ name: /^[[:punct:]]$/ }")
+
+ assert_equal 2, results.length
+ assert_equal ["Prism::CallNode"], results.map { |node| node.class.name }.uniq
+ end
+
+ def test_nil
+ results = scan("foo", "{ receiver: nil }")
+
+ assert_equal 1, results.length
+ end
+
+ def test_regexp_options
+ results = scan("@foo + @bar + @baz", "InstanceVariableReadNode[name: /^@B/i]")
+
+ assert_equal 2, results.length
+ end
+
+ def test_string_empty
+ results = scan("", "''")
+
+ assert_empty results
+ end
+
+ def test_symbol_empty
+ results = scan("", ":''")
+
+ assert_empty results
+ end
+
+ def test_symbol_plain
+ results = scan("@foo", "{ name: :\"@foo\" }")
+
+ assert_equal 1, results.length
+ end
+
+ def test_symbol
+ results = scan("@foo", "{ name: :@foo }")
+
+ assert_equal 1, results.length
+ end
+
+ private
+
+ def scan(source, query)
+ Prism::Pattern.new(query).scan(Prism.parse(source).value).to_a
+ end
+ end
+end
diff --git a/test/prism/ruby/reflection_test.rb b/test/prism/ruby/reflection_test.rb
new file mode 100644
index 0000000000..3ac462e1ac
--- /dev/null
+++ b/test/prism/ruby/reflection_test.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ReflectionTest < TestCase
+ def test_fields_for
+ fields = Reflection.fields_for(CallNode)
+ methods = CallNode.instance_methods(false)
+
+ fields.each do |field|
+ if field.is_a?(Reflection::FlagsField)
+ field.flags.each do |flag|
+ assert_includes methods, flag
+ end
+ else
+ assert_includes methods, field.name
+ end
+ end
+ end
+ end
+end
diff --git a/test/prism/ruby/relocation_test.rb b/test/prism/ruby/relocation_test.rb
new file mode 100644
index 0000000000..f8372afa6d
--- /dev/null
+++ b/test/prism/ruby/relocation_test.rb
@@ -0,0 +1,192 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class RelocationTest < TestCase
+ def test_repository_filepath
+ repository = Relocation.filepath(__FILE__).lines
+ declaration = Prism.parse_file(__FILE__).value.statements.body[1]
+
+ assert_equal 5, declaration.save(repository).start_line
+ end
+
+ def test_filepath
+ repository = Relocation.filepath(__FILE__).filepath
+ declaration = Prism.parse_file(__FILE__).value.statements.body[1]
+
+ assert_equal __FILE__, declaration.save(repository).filepath
+ end
+
+ def test_lines
+ source = "class Foo😀\nend"
+ repository = Relocation.string(source).lines
+ declaration = Prism.parse(source).value.statements.body.first
+
+ node_entry = declaration.save(repository)
+ location_entry = declaration.save_location(repository)
+
+ assert_equal 1, node_entry.start_line
+ assert_equal 2, node_entry.end_line
+
+ assert_equal 1, location_entry.start_line
+ assert_equal 2, location_entry.end_line
+ end
+
+ def test_offsets
+ source = "class Foo😀\nend"
+ repository = Relocation.string(source).offsets
+ declaration = Prism.parse(source).value.statements.body.first
+
+ node_entry = declaration.constant_path.save(repository)
+ location_entry = declaration.constant_path.save_location(repository)
+
+ assert_equal 6, node_entry.start_offset
+ assert_equal 13, node_entry.end_offset
+
+ assert_equal 6, location_entry.start_offset
+ assert_equal 13, location_entry.end_offset
+ end
+
+ def test_character_offsets
+ source = "class Foo😀\nend"
+ repository = Relocation.string(source).character_offsets
+ declaration = Prism.parse(source).value.statements.body.first
+
+ node_entry = declaration.constant_path.save(repository)
+ location_entry = declaration.constant_path.save_location(repository)
+
+ assert_equal 6, node_entry.start_character_offset
+ assert_equal 10, node_entry.end_character_offset
+
+ assert_equal 6, location_entry.start_character_offset
+ assert_equal 10, location_entry.end_character_offset
+ end
+
+ def test_code_unit_offsets
+ source = "class Foo😀\nend"
+ repository = Relocation.string(source).code_unit_offsets(Encoding::UTF_16LE)
+ declaration = Prism.parse(source).value.statements.body.first
+
+ node_entry = declaration.constant_path.save(repository)
+ location_entry = declaration.constant_path.save_location(repository)
+
+ assert_equal 6, node_entry.start_code_units_offset
+ assert_equal 11, node_entry.end_code_units_offset
+
+ assert_equal 6, location_entry.start_code_units_offset
+ assert_equal 11, location_entry.end_code_units_offset
+ end
+
+ def test_columns
+ source = "class Foo😀\nend"
+ repository = Relocation.string(source).columns
+ declaration = Prism.parse(source).value.statements.body.first
+
+ node_entry = declaration.constant_path.save(repository)
+ location_entry = declaration.constant_path.save_location(repository)
+
+ assert_equal 6, node_entry.start_column
+ assert_equal 13, node_entry.end_column
+
+ assert_equal 6, location_entry.start_column
+ assert_equal 13, location_entry.end_column
+ end
+
+ def test_character_columns
+ source = "class Foo😀\nend"
+ repository = Relocation.string(source).character_columns
+ declaration = Prism.parse(source).value.statements.body.first
+
+ node_entry = declaration.constant_path.save(repository)
+ location_entry = declaration.constant_path.save_location(repository)
+
+ assert_equal 6, node_entry.start_character_column
+ assert_equal 10, node_entry.end_character_column
+
+ assert_equal 6, location_entry.start_character_column
+ assert_equal 10, location_entry.end_character_column
+ end
+
+ def test_code_unit_columns
+ source = "class Foo😀\nend"
+ repository = Relocation.string(source).code_unit_columns(Encoding::UTF_16LE)
+ declaration = Prism.parse(source).value.statements.body.first
+
+ node_entry = declaration.constant_path.save(repository)
+ location_entry = declaration.constant_path.save_location(repository)
+
+ assert_equal 6, node_entry.start_code_units_column
+ assert_equal 11, node_entry.end_code_units_column
+
+ assert_equal 6, location_entry.start_code_units_column
+ assert_equal 11, location_entry.end_code_units_column
+ end
+
+ def test_leading_comments
+ source = "# leading\nclass Foo\nend"
+ repository = Relocation.string(source).leading_comments
+ declaration = Prism.parse(source).value.statements.body.first
+
+ node_entry = declaration.save(repository)
+ location_entry = declaration.save_location(repository)
+
+ assert_equal ["# leading"], node_entry.leading_comments.map(&:slice)
+ assert_equal ["# leading"], location_entry.leading_comments.map(&:slice)
+ end
+
+ def test_trailing_comments
+ source = "class Foo\nend\n# trailing"
+ repository = Relocation.string(source).trailing_comments
+ declaration = Prism.parse(source).value.statements.body.first
+
+ node_entry = declaration.save(repository)
+ location_entry = declaration.save_location(repository)
+
+ assert_equal ["# trailing"], node_entry.trailing_comments.map(&:slice)
+ assert_equal ["# trailing"], location_entry.trailing_comments.map(&:slice)
+ end
+
+ def test_comments
+ source = "# leading\nclass Foo\nend\n# trailing"
+ repository = Relocation.string(source).comments
+ declaration = Prism.parse(source).value.statements.body.first
+
+ node_entry = declaration.save(repository)
+ location_entry = declaration.save_location(repository)
+
+ assert_equal ["# leading", "# trailing"], node_entry.comments.map(&:slice)
+ assert_equal ["# leading", "# trailing"], location_entry.comments.map(&:slice)
+ end
+
+ def test_misconfiguration
+ assert_raise Relocation::Repository::ConfigurationError do
+ Relocation.string("").comments.leading_comments
+ end
+
+ assert_raise Relocation::Repository::ConfigurationError do
+ Relocation.string("").comments.trailing_comments
+ end
+
+ assert_raise Relocation::Repository::ConfigurationError do
+ Relocation.string("").code_unit_offsets(Encoding::UTF_8).code_unit_offsets(Encoding::UTF_16LE)
+ end
+
+ assert_raise Relocation::Repository::ConfigurationError do
+ Relocation.string("").lines.lines
+ end
+ end
+
+ def test_missing_values
+ source = "class Foo; end"
+ repository = Relocation.string(source).lines
+
+ declaration = Prism.parse(source).value.statements.body.first
+ entry = declaration.constant_path.save(repository)
+
+ assert_raise Relocation::Entry::MissingValueError do
+ entry.start_offset
+ end
+ end
+ end
+end
diff --git a/test/prism/ruby/ripper_test.rb b/test/prism/ruby/ripper_test.rb
new file mode 100644
index 0000000000..4fff630561
--- /dev/null
+++ b/test/prism/ruby/ripper_test.rb
@@ -0,0 +1,309 @@
+# frozen_string_literal: true
+
+return if RUBY_VERSION < "3.3" || RUBY_ENGINE != "ruby"
+
+require_relative "../test_helper"
+require "ripper"
+
+module Prism
+ class RipperTest < TestCase
+ # Skip these tests that Ripper is reporting the wrong results for.
+ incorrect = [
+ # Ripper incorrectly attributes the block to the keyword.
+ "seattlerb/block_return.txt",
+ "whitequark/return_block.txt",
+
+ # Ripper cannot handle named capture groups in regular expressions.
+ "regex.txt",
+
+ # Ripper fails to understand some structures that span across heredocs.
+ "spanning_heredoc.txt",
+
+ # Ripper interprets circular keyword arguments as method calls.
+ "3.4/circular_parameters.txt",
+
+ # Ripper doesn't emit `args_add_block` when endless method is prefixed by modifier.
+ "4.0/endless_methods_command_call.txt",
+
+ # https://bugs.ruby-lang.org/issues/21168#note-5
+ "command_method_call_2.txt",
+ ]
+
+ if RUBY_VERSION.start_with?("3.3.")
+ incorrect += [
+ "whitequark/lvar_injecting_match.txt",
+ "seattlerb/parse_pattern_058.txt",
+ "regex_char_width.txt",
+ ]
+ end
+
+ if RUBY_VERSION.start_with?("4.")
+ incorrect += [
+ # https://bugs.ruby-lang.org/issues/21945
+ "and_or_with_suffix.txt",
+ ]
+ end
+
+ # https://bugs.ruby-lang.org/issues/21669
+ incorrect << "4.1/void_value.txt"
+ # https://bugs.ruby-lang.org/issues/19107
+ incorrect << "4.1/trailing_comma_after_method_arguments.txt"
+
+ # Skip these tests that we haven't implemented yet.
+ omitted_sexp_raw = [
+ "bom_leading_space.txt",
+ "bom_spaces.txt",
+ "dos_endings.txt",
+ "heredocs_with_fake_newlines.txt",
+ "heredocs_with_ignored_newlines.txt",
+ "seattlerb/block_call_dot_op2_brace_block.txt",
+ "seattlerb/block_command_operation_colon.txt",
+ "seattlerb/block_command_operation_dot.txt",
+ "seattlerb/heredoc__backslash_dos_format.txt",
+ "seattlerb/heredoc_backslash_nl.txt",
+ "seattlerb/heredoc_nested.txt",
+ "seattlerb/heredoc_squiggly_blank_line_plus_interpolation.txt",
+ "tilde_heredocs.txt",
+ "unparser/corpus/semantic/dstr.txt",
+ "whitequark/dedenting_heredoc.txt",
+ "whitequark/parser_drops_truncated_parts_of_squiggly_heredoc.txt",
+ "whitequark/parser_slash_slash_n_escaping_in_literals.txt",
+ "whitequark/ruby_bug_18878.txt",
+ "whitequark/send_block_chain_cmd.txt",
+ "whitequark/slash_newline_in_heredocs.txt"
+ ]
+
+ omitted_lex = [
+ "heredoc_with_escaped_newline_at_start.txt",
+ "heredocs_with_fake_newlines.txt",
+ "indented_file_end.txt",
+ "spanning_heredoc_newlines.txt",
+ "whitequark/dedenting_heredoc.txt",
+ "whitequark/procarg0.txt",
+ ]
+
+ omitted_scan = [
+ "bom_leading_space.txt",
+ "bom_spaces.txt",
+ "dos_endings.txt",
+ "heredocs_with_fake_newlines.txt",
+ "rescue_modifier.txt",
+ "seattlerb/block_call_dot_op2_brace_block.txt",
+ "seattlerb/block_command_operation_colon.txt",
+ "seattlerb/block_command_operation_dot.txt",
+ "seattlerb/case_in.txt",
+ "seattlerb/heredoc__backslash_dos_format.txt",
+ "seattlerb/heredoc_backslash_nl.txt",
+ "seattlerb/heredoc_nested.txt",
+ "seattlerb/heredoc_squiggly_blank_line_plus_interpolation.txt",
+ "seattlerb/heredoc_squiggly_empty.txt",
+ "seattlerb/masgn_command_call.txt",
+ "seattlerb/messy_op_asgn_lineno.txt",
+ "seattlerb/op_asgn_primary_colon_const_command_call.txt",
+ "seattlerb/parse_pattern_076.txt",
+ "seattlerb/pct_w_heredoc_interp_nested.txt",
+ "tilde_heredocs.txt",
+ "unparser/corpus/literal/assignment.txt",
+ "unparser/corpus/literal/pattern.txt",
+ "unparser/corpus/semantic/dstr.txt",
+ "variables.txt",
+ "whitequark/dedenting_heredoc.txt",
+ "whitequark/masgn_nested.txt",
+ "whitequark/newline_in_hash_argument.txt",
+ "whitequark/numparam_ruby_bug_19025.txt",
+ "whitequark/op_asgn_cmd.txt",
+ "whitequark/parser_drops_truncated_parts_of_squiggly_heredoc.txt",
+ "whitequark/parser_slash_slash_n_escaping_in_literals.txt",
+ "whitequark/pattern_matching_nil_pattern.txt",
+ "whitequark/ruby_bug_12402.txt",
+ "whitequark/ruby_bug_18878.txt",
+ "whitequark/send_block_chain_cmd.txt",
+ "whitequark/slash_newline_in_heredocs.txt",
+ ]
+
+ Fixture.each_for_current_ruby(except: incorrect | omitted_sexp_raw) do |fixture|
+ define_method("#{fixture.test_name}_sexp_raw") { assert_ripper_sexp_raw(fixture.read) }
+ end
+
+ Fixture.each_for_current_ruby(except: incorrect | omitted_lex) do |fixture|
+ define_method("#{fixture.test_name}_lex") { assert_ripper_lex(fixture.read) }
+ end
+
+ def test_lex_ignored_missing_heredoc_end
+ ["", "-", "~"].each do |type|
+ source = "<<#{type}FOO\n"
+ assert_ripper_lex(source)
+
+ source = "<<#{type}'FOO'\n"
+ assert_ripper_lex(source)
+ end
+ end
+
+ UNSUPPORTED_EVENTS = %i[comma ignored_nl nl semicolon sp ignored_sp]
+ # Events that are currently not emitted
+ SUPPORTED_EVENTS = Translation::Ripper::EVENTS - UNSUPPORTED_EVENTS
+ # Events that assert against their line/column
+ CHECK_LOCATION_EVENTS = %i[kw op lbrace rbrace lbracket rbracket lparen rparen words_sep label_end]
+
+ module Events
+ attr_reader :events
+
+ def initialize(...)
+ super
+ @events = []
+ end
+
+ SUPPORTED_EVENTS.each do |event|
+ define_method(:"on_#{event}") do |*args|
+ if CHECK_LOCATION_EVENTS.include?(event)
+ @events << [event, lineno, column, *args]
+ else
+ @events << [event, *args]
+ end
+ super(*args)
+ end
+ end
+ end
+
+ class RipperEvents < Ripper
+ include Events
+ end
+
+ class PrismEvents < Translation::Ripper
+ include Events
+ end
+
+ class ObjectEvents < Translation::Ripper
+ OBJECT = BasicObject.new
+ SUPPORTED_EVENTS.each do |event|
+ define_method(:"on_#{event}") { |*args| OBJECT }
+ end
+ end
+
+ Fixture.each_for_current_ruby(except: incorrect | omitted_scan) do |fixture|
+ define_method("#{fixture.test_name}_events") do
+ source = fixture.read
+ # Similar to test/ripper/assert_parse_files.rb in CRuby
+ object_events = ObjectEvents.new(source)
+ assert_nothing_raised { object_events.parse }
+
+ ripper = RipperEvents.new(source, fixture.path)
+ prism = PrismEvents.new(source, fixture.path)
+ ripper.parse
+ prism.parse
+ # Check that the same events are emitted, regardless of order
+ assert_equal(ripper.events.sort_by(&:inspect), prism.events.sort_by(&:inspect))
+ end
+ end
+
+ def test_lexer
+ lexer = Translation::Ripper::Lexer.new("foo")
+ expected = [[1, 0], :on_ident, "foo", Translation::Ripper::EXPR_CMDARG]
+
+ assert_equal([expected], lexer.lex)
+ assert_equal(expected, lexer.parse[0].to_a)
+ assert_equal(lexer.parse[0].to_a, lexer.scan[0].to_a)
+
+ assert_equal(%i[on_int on_sp on_op], Translation::Ripper::Lexer.new("1 +").lex.map { |token| token[1] })
+ assert_raise(SyntaxError) { Translation::Ripper::Lexer.new("1 +").lex(raise_errors: true) }
+ end
+
+
+ # On syntax invalid code the output doesn't always match up
+ # In these cases we just want to make sure that it doesn't raise.
+ def test_lex_invalid_syntax
+ assert_nothing_raised do
+ Translation::Ripper.lex('scan/\p{alpha}/')
+ end
+
+ assert_equal(Ripper.lex('if;)'), Translation::Ripper.lex('if;)'))
+ end
+
+ def test_tokenize
+ source = "foo;1;BAZ"
+ assert_equal(Ripper.tokenize(source), Translation::Ripper.tokenize(source))
+ end
+
+ def test_encoding
+ source = '"わたし"'.encode(Encoding::Windows_31J)
+ assert_equal(Ripper.tokenize(source), Translation::Ripper.tokenize(source))
+ assert_equal(Ripper.sexp(source), Translation::Ripper.sexp(source))
+ end
+
+ def test_sexp_coercion
+ string_like = Object.new
+ def string_like.to_str
+ "a"
+ end
+ assert_equal Ripper.sexp(string_like), Translation::Ripper.sexp(string_like)
+
+ File.open(__FILE__) do |file1|
+ File.open(__FILE__) do |file2|
+ assert_equal Ripper.sexp(file1), Translation::Ripper.sexp(file2)
+ end
+ end
+
+ File.open(__FILE__) do |file1|
+ File.open(__FILE__) do |file2|
+ object1_with_gets = Object.new
+ object1_with_gets.define_singleton_method(:gets) do
+ file1.gets
+ end
+
+ object2_with_gets = Object.new
+ object2_with_gets.define_singleton_method(:gets) do
+ file2.gets
+ end
+
+ assert_equal Ripper.sexp(object1_with_gets), Translation::Ripper.sexp(object2_with_gets)
+ end
+ end
+ end
+
+ def test_lex_coersion
+ string_like = Object.new
+ def string_like.to_str
+ "a"
+ end
+ assert_equal Ripper.lex(string_like), Translation::Ripper.lex(string_like)
+ end
+
+ # Check that the hardcoded values don't change without us noticing.
+ def test_internals
+ actual = Translation::Ripper.constants.select { |name| name.start_with?("EXPR_") }.sort
+ expected = Ripper.constants.select { |name| name.start_with?("EXPR_") }.sort
+
+ assert_equal(expected, actual)
+ expected.zip(actual).each do |ripper, prism|
+ assert_equal(Ripper.const_get(ripper), Translation::Ripper.const_get(prism))
+ end
+ end
+
+ private
+
+ def assert_ripper_sexp_raw(source)
+ assert_equal Ripper.sexp_raw(source), Prism::Translation::Ripper.sexp_raw(source)
+ end
+
+ def assert_ripper_lex(source)
+ prism = Translation::Ripper.lex(source)
+ ripper = Ripper.lex(source)
+
+ # Prism emits tokens by their order in the code, not in parse order
+ ripper.sort_by! { |elem| elem[0] }
+
+ [prism.size, ripper.size].max.times do |index|
+ expected = ripper[index]
+ actual = prism[index]
+
+ # There are some tokens that have slightly different state that do not
+ # effect the parse tree, so they may not match.
+ if expected && actual && expected[1] == actual[1] && %i[on_comment on_heredoc_end on_embexpr_end on_sp].include?(expected[1])
+ expected[3] = actual[3] = nil
+ end
+
+ assert_equal(expected, actual)
+ end
+ end
+ end
+end
diff --git a/test/prism/ruby/ruby_parser_test.rb b/test/prism/ruby/ruby_parser_test.rb
new file mode 100644
index 0000000000..bc89bdae72
--- /dev/null
+++ b/test/prism/ruby/ruby_parser_test.rb
@@ -0,0 +1,140 @@
+# frozen_string_literal: true
+
+return if RUBY_ENGINE == "jruby"
+
+require_relative "../test_helper"
+
+begin
+ require "ruby_parser"
+rescue LoadError
+ # In CRuby's CI, we're not going to test against the ruby_parser gem because
+ # we don't want to have to install it. So in this case we'll just skip this
+ # test.
+ return
+end
+
+module Prism
+ class RubyParserTest < TestCase
+ todos = [
+ "character_literal.txt",
+ "encoding_euc_jp.txt",
+ "regex_char_width.txt",
+ "seattlerb/masgn_colon3.txt",
+ "seattlerb/messy_op_asgn_lineno.txt",
+ "seattlerb/op_asgn_primary_colon_const_command_call.txt",
+ "seattlerb/regexp_esc_C_slash.txt",
+ "seattlerb/str_lit_concat_bad_encodings.txt",
+ "strings.txt",
+ "unescaping.txt",
+ "whitequark/masgn_const.txt",
+ "whitequark/pattern_matching_constants.txt",
+ "whitequark/pattern_matching_single_match.txt",
+ "whitequark/ruby_bug_12402.txt",
+ ]
+
+ # https://github.com/seattlerb/ruby_parser/issues/344
+ failures = [
+ "alias.txt",
+ "dsym_str.txt",
+ "dos_endings.txt",
+ "heredoc_dedent_line_continuation.txt",
+ "heredoc_percent_q_newline_delimiter.txt",
+ "heredocs_with_fake_newlines.txt",
+ "heredocs_with_ignored_newlines.txt",
+ "method_calls.txt",
+ "methods.txt",
+ "multi_write.txt",
+ "not.txt",
+ "patterns.txt",
+ "regex.txt",
+ "seattlerb/and_multi.txt",
+ "seattlerb/heredoc__backslash_dos_format.txt",
+ "seattlerb/heredoc_bad_hex_escape.txt",
+ "seattlerb/heredoc_bad_oct_escape.txt",
+ "seattlerb/heredoc_with_extra_carriage_horrible_mix.txt",
+ "seattlerb/heredoc_with_extra_carriage_returns_windows.txt",
+ "seattlerb/heredoc_with_only_carriage_returns_windows.txt",
+ "seattlerb/heredoc_with_only_carriage_returns.txt",
+ "spanning_heredoc_newlines.txt",
+ "spanning_heredoc.txt",
+ "symbols.txt",
+ "tilde_heredocs.txt",
+ "unary_method_calls.txt",
+ "unparser/corpus/literal/literal.txt",
+ "while.txt",
+ "whitequark/cond_eflipflop.txt",
+ "whitequark/cond_iflipflop.txt",
+ "whitequark/cond_match_current_line.txt",
+ "whitequark/dedenting_heredoc.txt",
+ "whitequark/lvar_injecting_match.txt",
+ "whitequark/not.txt",
+ "whitequark/numparam_ruby_bug_19025.txt",
+ "whitequark/op_asgn_cmd.txt",
+ "whitequark/parser_bug_640.txt",
+ "whitequark/parser_slash_slash_n_escaping_in_literals.txt",
+ "whitequark/pattern_matching_single_line_allowed_omission_of_parentheses.txt",
+ "whitequark/pattern_matching_single_line.txt",
+ "whitequark/ruby_bug_11989.txt",
+ "whitequark/ruby_bug_18878.txt",
+ "whitequark/ruby_bug_19281.txt",
+ "whitequark/slash_newline_in_heredocs.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.3-4.0/void_value.txt",
+
+ # https://bugs.ruby-lang.org/issues/21168#note-5
+ "command_method_call_2.txt",
+ ]
+
+ Fixture.each_for_version(version: "3.3", except: failures) do |fixture|
+ define_method(fixture.test_name) do
+ assert_ruby_parser(fixture, todos.include?(fixture.path))
+ end
+ end
+
+ private
+
+ def assert_ruby_parser(fixture, allowed_failure)
+ source = fixture.read
+ expected = ignore_warnings { ::RubyParser.new.parse(source, fixture.path) }
+ actual = Prism::Translation::RubyParser.new.parse(source, fixture.path)
+ on_failure = -> { message(expected, actual) }
+
+ if !allowed_failure
+ assert_equal(expected, actual, on_failure)
+
+ unless actual.nil?
+ assert_equal(expected.line, actual.line, on_failure)
+ assert_equal(expected.file, actual.file, on_failure)
+ end
+ elsif expected == actual && expected.line && actual.line && expected.file == actual.file
+ puts "#{name} now passes"
+ end
+ end
+
+ def message(expected, actual)
+ if expected == actual
+ nil
+ elsif expected.is_a?(Sexp) && actual.is_a?(Sexp)
+ if expected.line != actual.line
+ "expected: (#{expected.inspect} line=#{expected.line}), actual: (#{actual.inspect} line=#{actual.line})"
+ elsif expected.file != actual.file
+ "expected: (#{expected.inspect} file=#{expected.file}), actual: (#{actual.inspect} file=#{actual.file})"
+ elsif expected.length != actual.length
+ "expected: (#{expected.inspect} length=#{expected.length}), actual: (#{actual.inspect} length=#{actual.length})"
+ else
+ expected.zip(actual).find do |expected_field, actual_field|
+ result = message(expected_field, actual_field)
+ break result if result
+ end
+ end
+ else
+ "expected: #{expected.inspect}, actual: #{actual.inspect}"
+ end
+ end
+ end
+end
diff --git a/test/prism/ruby/source_test.rb b/test/prism/ruby/source_test.rb
new file mode 100644
index 0000000000..f7cf4fe83a
--- /dev/null
+++ b/test/prism/ruby/source_test.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class SourceTest < TestCase
+ def test_byte_offset
+ source = Prism.parse(<<~SRC).source
+ abcd
+ efgh
+ ijkl
+ SRC
+
+ assert_equal 0, source.byte_offset(1, 0)
+ assert_equal 5, source.byte_offset(2, 0)
+ assert_equal 10, source.byte_offset(3, 0)
+ assert_equal 15, source.byte_offset(4, 0)
+
+ error = assert_raise(ArgumentError) { source.byte_offset(5, 0) }
+ assert_equal "line 5 is out of range", error.message
+
+ error = assert_raise(ArgumentError) { source.byte_offset(0, 0) }
+ assert_equal "line 0 is out of range", error.message
+
+ error = assert_raise(ArgumentError) { source.byte_offset(-1, 0) }
+ assert_equal "line -1 is out of range", error.message
+ end
+
+ def test_byte_offset_with_start_line
+ source = Prism.parse(<<~SRC, line: 11).source
+ abcd
+ efgh
+ ijkl
+ SRC
+
+ assert_equal 0, source.byte_offset(11, 0)
+ assert_equal 5, source.byte_offset(12, 0)
+ assert_equal 10, source.byte_offset(13, 0)
+ assert_equal 15, source.byte_offset(14, 0)
+
+ error = assert_raise(ArgumentError) { source.byte_offset(15, 0) }
+ assert_equal "line 15 is out of range", error.message
+
+ error = assert_raise(ArgumentError) { source.byte_offset(10, 0) }
+ assert_equal "line 10 is out of range", error.message
+
+ error = assert_raise(ArgumentError) { source.byte_offset(9, 0) }
+ assert_equal "line 9 is out of range", error.message
+ end
+ end
+end
diff --git a/test/prism/ruby/string_query_test.rb b/test/prism/ruby/string_query_test.rb
new file mode 100644
index 0000000000..aa50c10ff3
--- /dev/null
+++ b/test/prism/ruby/string_query_test.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class StringQueryTest < TestCase
+ def test_local?
+ assert_predicate StringQuery.new("a"), :local?
+ assert_predicate StringQuery.new("a1"), :local?
+ assert_predicate StringQuery.new("self"), :local?
+
+ assert_predicate StringQuery.new("_a"), :local?
+ assert_predicate StringQuery.new("_1"), :local?
+
+ assert_predicate StringQuery.new("😀"), :local?
+ assert_predicate StringQuery.new("ア".encode("Windows-31J")), :local?
+
+ refute_predicate StringQuery.new("1"), :local?
+ refute_predicate StringQuery.new("A"), :local?
+ end
+
+ def test_constant?
+ assert_predicate StringQuery.new("A"), :constant?
+ assert_predicate StringQuery.new("A1"), :constant?
+ assert_predicate StringQuery.new("A_B"), :constant?
+ assert_predicate StringQuery.new("BEGIN"), :constant?
+
+ assert_predicate StringQuery.new("À"), :constant?
+ assert_predicate StringQuery.new("A".encode("US-ASCII")), :constant?
+
+ refute_predicate StringQuery.new("a"), :constant?
+ refute_predicate StringQuery.new("1"), :constant?
+ end
+
+ def test_method_name?
+ assert_predicate StringQuery.new("a"), :method_name?
+ assert_predicate StringQuery.new("A"), :method_name?
+ assert_predicate StringQuery.new("__FILE__"), :method_name?
+
+ assert_predicate StringQuery.new("a?"), :method_name?
+ assert_predicate StringQuery.new("a!"), :method_name?
+ assert_predicate StringQuery.new("a="), :method_name?
+
+ assert_predicate StringQuery.new("+"), :method_name?
+ assert_predicate StringQuery.new("<<"), :method_name?
+ assert_predicate StringQuery.new("==="), :method_name?
+
+ assert_predicate StringQuery.new("_0"), :method_name?
+
+ refute_predicate StringQuery.new("1"), :method_name?
+ refute_predicate StringQuery.new("_1"), :method_name?
+ end
+
+ def test_invalid_encoding
+ assert_raise ArgumentError do
+ StringQuery.new("A".encode("UTF-16LE")).local?
+ end
+ end
+ end
+end
diff --git a/test/prism/ruby/tunnel_test.rb b/test/prism/ruby/tunnel_test.rb
new file mode 100644
index 0000000000..0214681604
--- /dev/null
+++ b/test/prism/ruby/tunnel_test.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class TunnelTest < TestCase
+ def test_tunnel
+ program = Prism.parse("foo(1) +\n bar(2, 3) +\n baz(3, 4, 5)").value
+
+ tunnel = program.tunnel(1, 4).last
+ assert_kind_of IntegerNode, tunnel
+ assert_equal 1, tunnel.value
+
+ tunnel = program.tunnel(2, 6).last
+ assert_kind_of IntegerNode, tunnel
+ assert_equal 2, tunnel.value
+
+ tunnel = program.tunnel(3, 9).last
+ assert_kind_of IntegerNode, tunnel
+ assert_equal 4, tunnel.value
+
+ tunnel = program.tunnel(3, 8)
+ assert_equal [ProgramNode, StatementsNode, CallNode, ArgumentsNode, CallNode, ArgumentsNode], tunnel.map(&:class)
+ end
+ end
+end
diff --git a/test/prism/snippets_test.rb b/test/prism/snippets_test.rb
new file mode 100644
index 0000000000..3c28d27a25
--- /dev/null
+++ b/test/prism/snippets_test.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require_relative "test_helper"
+
+module Prism
+ class SnippetsTest < TestCase
+ except = [
+ "encoding_binary.txt",
+ "newline_terminated.txt",
+ "seattlerb/begin_rescue_else_ensure_no_bodies.txt",
+ "seattlerb/case_in.txt",
+ "seattlerb/parse_line_defn_no_parens.txt",
+ "seattlerb/pct_nl.txt",
+ "seattlerb/str_heredoc_interp.txt",
+ "spanning_heredoc_newlines.txt",
+ "unparser/corpus/semantic/dstr.txt",
+ "whitequark/dedenting_heredoc.txt",
+ "whitequark/multiple_pattern_matches.txt"
+ ]
+
+ Fixture.each_with_all_versions(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, version)
+ fixture.read.split(/(?<=\S)\n\n(?=\S)/).each do |snippet|
+ snippet = snippet.rstrip
+
+ result = Prism.parse(snippet, filepath: fixture.path, version: version)
+ assert result.success?
+
+ if !ENV["PRISM_BUILD_MINIMAL"]
+ dumped = Prism.dump(snippet, filepath: fixture.path, version: version)
+ assert_equal_nodes(result.value, Prism.load(snippet, dumped, version: version).value)
+ end
+ end
+ end
+ end
+end
diff --git a/test/prism/test_helper.rb b/test/prism/test_helper.rb
new file mode 100644
index 0000000000..406582c0a5
--- /dev/null
+++ b/test/prism/test_helper.rb
@@ -0,0 +1,386 @@
+# frozen_string_literal: true
+
+require "prism"
+require "pp"
+require "stringio"
+require "test/unit"
+require "tempfile"
+
+puts "Using prism backend: #{Prism::BACKEND}" if ENV["PRISM_FFI_BACKEND"]
+
+# It is useful to have a diff even if the strings to compare are big
+# However, ruby/ruby does not have a version of Test::Unit with access to
+# max_diff_target_string_size
+if defined?(Test::Unit::Assertions::AssertionMessage)
+ Test::Unit::Assertions::AssertionMessage.max_diff_target_string_size = 5000
+end
+
+module Prism
+ # A convenience method for retrieving the first statement in the source string
+ # parsed by Prism.
+ def self.parse_statement(source, **options)
+ parse(source, **options).value.statements.body.first
+ end
+
+ class ParseResult < Result
+ # Returns the first statement in the body of the parsed source.
+ def statement
+ value.statements.body.first
+ end
+ end
+
+ class TestCase < ::Test::Unit::TestCase
+ # We have a set of fixtures that we use to test various aspects of the
+ # parser. They are all represented as .txt files under the
+ # test/prism/fixtures directory. Typically in test files you will find calls
+ # to Fixture.each which yields Fixture objects to the given block. These
+ # are used to define test methods that assert against each fixture in some
+ # way.
+ class Fixture
+ BASE = ENV.fetch("FIXTURE_BASE", File.join(__dir__, "fixtures"))
+
+ attr_reader :path
+
+ def initialize(path)
+ @path = path
+ end
+
+ def read
+ File.read(full_path, binmode: true, external_encoding: Encoding::UTF_8)
+ end
+
+ def full_path
+ File.join(BASE, path)
+ end
+
+ def snapshot_path
+ File.join(File.expand_path("../..", __dir__), "snapshots", path)
+ end
+
+ def test_name(version = nil)
+ if version
+ :"test_#{version}_#{path}"
+ else
+ :"test_#{path}"
+ end
+ end
+
+ def self.each(except: [], &block)
+ glob_pattern = ENV.fetch("FOCUS") { custom_base_path? ? File.join("**", "*.rb") : File.join("**", "*.txt") }
+ paths = Dir[glob_pattern, base: BASE] - except
+ paths.each { |path| yield Fixture.new(path) }
+ end
+
+ def self.each_for_version(except: [], version:, &block)
+ each(except: except) do |fixture|
+ next unless TestCase.ruby_versions_for(fixture.path).include?(version)
+ yield fixture
+ end
+ end
+
+ def self.each_for_current_ruby(except: [], &block)
+ each_for_version(except: except, version: CURRENT_MAJOR_MINOR, &block)
+ end
+
+ def self.each_with_all_versions(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
+ end
+
+ # Yield each encoding that we want to test, along with a range of the
+ # codepoints that should be tested.
+ def self.each_encoding
+ codepoints_1byte = 0...0x100
+
+ yield Encoding::ASCII_8BIT, codepoints_1byte
+ yield Encoding::US_ASCII, codepoints_1byte
+
+ if !ENV["PRISM_BUILD_MINIMAL"]
+ yield Encoding::Windows_1253, codepoints_1byte
+ end
+
+ # By default we don't test every codepoint in these encodings because it
+ # takes a very long time.
+ return unless ENV["PRISM_TEST_ALL_ENCODINGS"]
+
+ yield Encoding::CP850, codepoints_1byte
+ yield Encoding::CP852, codepoints_1byte
+ yield Encoding::CP855, codepoints_1byte
+ yield Encoding::GB1988, codepoints_1byte
+ yield Encoding::IBM437, codepoints_1byte
+ yield Encoding::IBM720, codepoints_1byte
+ yield Encoding::IBM737, codepoints_1byte
+ yield Encoding::IBM775, codepoints_1byte
+ yield Encoding::IBM852, codepoints_1byte
+ yield Encoding::IBM855, codepoints_1byte
+ yield Encoding::IBM857, codepoints_1byte
+ yield Encoding::IBM860, codepoints_1byte
+ yield Encoding::IBM861, codepoints_1byte
+ yield Encoding::IBM862, codepoints_1byte
+ yield Encoding::IBM863, codepoints_1byte
+ yield Encoding::IBM864, codepoints_1byte
+ yield Encoding::IBM865, codepoints_1byte
+ yield Encoding::IBM866, codepoints_1byte
+ yield Encoding::IBM869, codepoints_1byte
+ yield Encoding::ISO_8859_1, codepoints_1byte
+ yield Encoding::ISO_8859_2, codepoints_1byte
+ yield Encoding::ISO_8859_3, codepoints_1byte
+ yield Encoding::ISO_8859_4, codepoints_1byte
+ yield Encoding::ISO_8859_5, codepoints_1byte
+ yield Encoding::ISO_8859_6, codepoints_1byte
+ yield Encoding::ISO_8859_7, codepoints_1byte
+ yield Encoding::ISO_8859_8, codepoints_1byte
+ yield Encoding::ISO_8859_9, codepoints_1byte
+ yield Encoding::ISO_8859_10, codepoints_1byte
+ yield Encoding::ISO_8859_11, codepoints_1byte
+ yield Encoding::ISO_8859_13, codepoints_1byte
+ yield Encoding::ISO_8859_14, codepoints_1byte
+ yield Encoding::ISO_8859_15, codepoints_1byte
+ yield Encoding::ISO_8859_16, codepoints_1byte
+ yield Encoding::KOI8_R, codepoints_1byte
+ yield Encoding::KOI8_U, codepoints_1byte
+ yield Encoding::MACCENTEURO, codepoints_1byte
+ yield Encoding::MACCROATIAN, codepoints_1byte
+ yield Encoding::MACCYRILLIC, codepoints_1byte
+ yield Encoding::MACGREEK, codepoints_1byte
+ yield Encoding::MACICELAND, codepoints_1byte
+ yield Encoding::MACROMAN, codepoints_1byte
+ yield Encoding::MACROMANIA, codepoints_1byte
+ yield Encoding::MACTHAI, codepoints_1byte
+ yield Encoding::MACTURKISH, codepoints_1byte
+ yield Encoding::MACUKRAINE, codepoints_1byte
+ yield Encoding::TIS_620, codepoints_1byte
+ yield Encoding::Windows_1250, codepoints_1byte
+ yield Encoding::Windows_1251, codepoints_1byte
+ yield Encoding::Windows_1252, codepoints_1byte
+ yield Encoding::Windows_1254, codepoints_1byte
+ yield Encoding::Windows_1255, codepoints_1byte
+ yield Encoding::Windows_1256, codepoints_1byte
+ yield Encoding::Windows_1257, codepoints_1byte
+ yield Encoding::Windows_1258, codepoints_1byte
+ yield Encoding::Windows_874, codepoints_1byte
+
+ codepoints_2bytes = 0...0x10000
+
+ yield Encoding::Big5, codepoints_2bytes
+ yield Encoding::Big5_HKSCS, codepoints_2bytes
+ yield Encoding::Big5_UAO, codepoints_2bytes
+ yield Encoding::CP949, codepoints_2bytes
+ yield Encoding::CP950, codepoints_2bytes
+ yield Encoding::CP951, codepoints_2bytes
+ yield Encoding::EUC_KR, codepoints_2bytes
+ yield Encoding::GBK, codepoints_2bytes
+ yield Encoding::GB12345, codepoints_2bytes
+ yield Encoding::GB2312, codepoints_2bytes
+ yield Encoding::MACJAPANESE, codepoints_2bytes
+ yield Encoding::Shift_JIS, codepoints_2bytes
+ yield Encoding::SJIS_DoCoMo, codepoints_2bytes
+ yield Encoding::SJIS_KDDI, codepoints_2bytes
+ yield Encoding::SJIS_SoftBank, codepoints_2bytes
+ yield Encoding::Windows_31J, codepoints_2bytes
+
+ codepoints_unicode = (0...0x110000)
+
+ yield Encoding::UTF_8, codepoints_unicode
+ yield Encoding::UTF8_MAC, codepoints_unicode
+ yield Encoding::UTF8_DoCoMo, codepoints_unicode
+ yield Encoding::UTF8_KDDI, codepoints_unicode
+ yield Encoding::UTF8_SoftBank, codepoints_unicode
+ yield Encoding::CESU_8, codepoints_unicode
+
+ codepoints_eucjp = [
+ *(0...0x10000),
+ *(0...0x10000).map { |bytes| bytes | 0x8F0000 }
+ ]
+
+ yield Encoding::CP51932, codepoints_eucjp
+ yield Encoding::EUC_JP, codepoints_eucjp
+ yield Encoding::EUCJP_MS, codepoints_eucjp
+ yield Encoding::EUC_JIS_2004, codepoints_eucjp
+
+ codepoints_emacs_mule = [
+ *(0...0x80),
+ *((0x81...0x90).flat_map { |byte1| (0x90...0x100).map { |byte2| byte1 << 8 | byte2 } }),
+ *((0x90...0x9C).flat_map { |byte1| (0xA0...0x100).flat_map { |byte2| (0xA0...0x100).flat_map { |byte3| byte1 << 16 | byte2 << 8 | byte3 } } }),
+ *((0xF0...0xF5).flat_map { |byte2| (0xA0...0x100).flat_map { |byte3| (0xA0...0x100).flat_map { |byte4| 0x9C << 24 | byte3 << 16 | byte3 << 8 | byte4 } } }),
+ ]
+
+ yield Encoding::EMACS_MULE, codepoints_emacs_mule
+ yield Encoding::STATELESS_ISO_2022_JP, codepoints_emacs_mule
+ yield Encoding::STATELESS_ISO_2022_JP_KDDI, codepoints_emacs_mule
+
+ codepoints_gb18030 = [
+ *(0...0x80),
+ *((0x81..0xFE).flat_map { |byte1| (0x40...0x100).map { |byte2| byte1 << 8 | byte2 } }),
+ *((0x81..0xFE).flat_map { |byte1| (0x30...0x40).flat_map { |byte2| (0x81..0xFE).flat_map { |byte3| (0x2F...0x41).map { |byte4| byte1 << 24 | byte2 << 16 | byte3 << 8 | byte4 } } } }),
+ ]
+
+ yield Encoding::GB18030, codepoints_gb18030
+
+ codepoints_euc_tw = [
+ *(0..0x7F),
+ *(0xA1..0xFF).flat_map { |byte1| (0xA1..0xFF).map { |byte2| (byte1 << 8) | byte2 } },
+ *(0xA1..0xB0).flat_map { |byte2| (0xA1..0xFF).flat_map { |byte3| (0xA1..0xFF).flat_map { |byte4| 0x8E << 24 | byte2 << 16 | byte3 << 8 | byte4 } } }
+ ]
+
+ yield Encoding::EUC_TW, codepoints_euc_tw
+ end
+
+ # True if the current platform is Windows.
+ 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 4.0 4.1]
+
+ # `RUBY_VERSION` with the patch version excluded
+ CURRENT_MAJOR_MINOR = RUBY_VERSION.split(".")[0, 2].join(".")
+
+ # 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
+
+ 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
+ # Check that the given source is valid syntax by compiling it with RubyVM.
+ def check_syntax(source)
+ ignore_warnings { RubyVM::InstructionSequence.compile(source) }
+ end
+
+ # Assert that the given source is valid Ruby syntax by attempting to
+ # compile it, and then implicitly checking that it does not raise an
+ # syntax errors.
+ def assert_valid_syntax(source)
+ check_syntax(source)
+ end
+
+ # Refute that the given source is invalid Ruby syntax by attempting to
+ # compile it and asserting that it raises a SyntaxError.
+ def refute_valid_syntax(source)
+ assert_raise(SyntaxError) { check_syntax(source) }
+ end
+ else
+ def assert_valid_syntax(source)
+ end
+
+ def refute_valid_syntax(source)
+ end
+ end
+
+ # CRuby has this same method, so define it so that we don't accidentally
+ # break CRuby CI.
+ def assert_raises(*args, &block)
+ raise "Use assert_raise instead"
+ end
+
+ def assert_equal_nodes(expected, actual, compare_location: true, parent: nil)
+ assert_equal expected.class, actual.class
+
+ case expected
+ when Array
+ assert_equal(
+ expected.size,
+ actual.size,
+ -> { "Arrays were different sizes. Parent: #{parent.pretty_inspect}" }
+ )
+
+ expected.zip(actual).each do |(expected_element, actual_element)|
+ assert_equal_nodes(
+ expected_element,
+ actual_element,
+ compare_location: compare_location,
+ parent: actual
+ )
+ end
+ when SourceFileNode
+ expected_deconstruct = expected.deconstruct_keys(nil)
+ actual_deconstruct = actual.deconstruct_keys(nil)
+ assert_equal expected_deconstruct.keys, actual_deconstruct.keys
+
+ # Filepaths can be different if test suites were run on different
+ # machines. We accommodate for this by comparing the basenames, and not
+ # the absolute filepaths.
+ expected_filepath = expected_deconstruct.delete(:filepath)
+ actual_filepath = actual_deconstruct.delete(:filepath)
+
+ assert_equal expected_deconstruct, actual_deconstruct
+ assert_equal File.basename(expected_filepath), File.basename(actual_filepath)
+ when Node
+ deconstructed_expected = expected.deconstruct_keys(nil)
+ deconstructed_actual = actual.deconstruct_keys(nil)
+ assert_equal deconstructed_expected.keys, deconstructed_actual.keys
+
+ deconstructed_expected.each_key do |key|
+ assert_equal_nodes(
+ deconstructed_expected[key],
+ deconstructed_actual[key],
+ compare_location: compare_location,
+ parent: actual
+ )
+ end
+ when Location
+ assert_operator actual.start_offset, :<=, actual.end_offset, -> {
+ "start_offset > end_offset for #{actual.inspect}, parent is #{parent.pretty_inspect}"
+ }
+
+ if compare_location
+ assert_equal(
+ expected.start_offset,
+ actual.start_offset,
+ -> { "Start locations were different. Parent: #{parent.pretty_inspect}" }
+ )
+
+ assert_equal(
+ expected.end_offset,
+ actual.end_offset,
+ -> { "End locations were different. Parent: #{parent.pretty_inspect}" }
+ )
+ end
+ else
+ assert_equal expected, actual
+ end
+ end
+
+ def capture_warnings
+ $stderr = StringIO.new
+ yield
+ $stderr.string
+ ensure
+ $stderr = STDERR
+ end
+
+ def ignore_warnings
+ capture_warnings { return yield }
+ end
+ end
+end
diff --git a/test/prism/unescape_test.rb b/test/prism/unescape_test.rb
new file mode 100644
index 0000000000..d241f28c08
--- /dev/null
+++ b/test/prism/unescape_test.rb
@@ -0,0 +1,245 @@
+# frozen_string_literal: true
+
+require_relative "test_helper"
+
+return if Prism::BACKEND == :FFI
+return if RUBY_VERSION < "3.1.0"
+return if RUBY_VERSION >= "3.4.0"
+
+module Prism
+ class UnescapeTest < TestCase
+ module Context
+ class Base
+ attr_reader :left, :right
+
+ def initialize(left, right)
+ @left = left
+ @right = right
+ end
+
+ def name
+ "#{left}#{right}".delete("\n")
+ end
+
+ private
+
+ def code(escape)
+ "#{left}\\#{escape}#{right}".b
+ end
+
+ def ruby(escape)
+ previous, $VERBOSE = $VERBOSE, nil
+
+ begin
+ yield eval(code(escape))
+ rescue SyntaxError
+ :error
+ ensure
+ $VERBOSE = previous
+ end
+ end
+
+ def prism(escape)
+ result = Prism.parse(code(escape), encoding: "binary")
+
+ if result.success?
+ yield result.statement
+ else
+ :error
+ end
+ end
+
+ def `(command)
+ command
+ end
+ end
+
+ class List < Base
+ def ruby_result(escape)
+ ruby(escape) { |value| value.first.to_s }
+ end
+
+ def prism_result(escape)
+ prism(escape) { |node| node.elements.first.unescaped }
+ end
+ end
+
+ class Symbol < Base
+ def ruby_result(escape)
+ ruby(escape, &:to_s)
+ end
+
+ def prism_result(escape)
+ prism(escape, &:unescaped)
+ end
+ end
+
+ class String < Base
+ def ruby_result(escape)
+ ruby(escape, &:itself)
+ end
+
+ def prism_result(escape)
+ prism(escape, &:unescaped)
+ end
+ end
+
+ class Heredoc < Base
+ def ruby_result(escape)
+ ruby(escape, &:itself)
+ end
+
+ def prism_result(escape)
+ prism(escape) do |node|
+ case node.type
+ when :interpolated_string_node, :interpolated_x_string_node
+ node.parts.flat_map(&:unescaped).join
+ else
+ node.unescaped
+ end
+ end
+ end
+ end
+
+ class RegExp < Base
+ def ruby_result(escape)
+ ruby(escape, &:source)
+ end
+
+ def prism_result(escape)
+ prism(escape, &:unescaped)
+ end
+ end
+ end
+
+ def test_char; assert_context(Context::String.new("?", "")); end
+ def test_sqte; assert_context(Context::String.new("'", "'")); end
+ def test_dqte; assert_context(Context::String.new("\"", "\"")); end
+ def test_lwrq; assert_context(Context::String.new("%q[", "]")); end
+ def test_uprq; assert_context(Context::String.new("%Q[", "]")); end
+ def test_dstr; assert_context(Context::String.new("%[", "]")); end
+ def test_xstr; assert_context(Context::String.new("`", "`")); end
+ def test_lwrx; assert_context(Context::String.new("%x[", "]")); end
+ def test_h0_1; assert_context(Context::String.new("<<H\n", "\nH")); end
+ def test_h0_2; assert_context(Context::String.new("<<'H'\n", "\nH")); end
+ def test_h0_3; assert_context(Context::String.new("<<\"H\"\n", "\nH")); end
+ def test_h0_4; assert_context(Context::String.new("<<`H`\n", "\nH")); end
+ def test_hd_1; assert_context(Context::String.new("<<-H\n", "\nH")); end
+ def test_hd_2; assert_context(Context::String.new("<<-'H'\n", "\nH")); end
+ def test_hd_3; assert_context(Context::String.new("<<-\"H\"\n", "\nH")); end
+ def test_hd_4; assert_context(Context::String.new("<<-`H`\n", "\nH")); end
+ def test_ht_1; assert_context(Context::Heredoc.new("<<~H\n", "\nH")); end
+ def test_ht_2; assert_context(Context::Heredoc.new("<<~'H'\n", "\nH")); end
+ def test_ht_3; assert_context(Context::Heredoc.new("<<~\"H\"\n", "\nH")); end
+ def test_ht_4; assert_context(Context::Heredoc.new("<<~`H`\n", "\nH")); end
+ def test_pw_1; assert_context(Context::List.new("%w[", "]")); end
+ def test_pw_2; assert_context(Context::List.new("%w<", ">")); end
+ def test_uprw; assert_context(Context::List.new("%W[", "]")); end
+ def test_lwri; assert_context(Context::List.new("%i[", "]")); end
+ def test_upri; assert_context(Context::List.new("%I[", "]")); end
+ def test_lwrs; assert_context(Context::Symbol.new("%s[", "]")); end
+ def test_sym1; assert_context(Context::Symbol.new(":'", "'")); end
+ def test_sym2; assert_context(Context::Symbol.new(":\"", "\"")); end
+ def test_reg1; assert_context(Context::RegExp.new("/", "/")); end
+ def test_reg2; assert_context(Context::RegExp.new("%r[", "]")); end
+ def test_reg3; assert_context(Context::RegExp.new("%r<", ">")); end
+ def test_reg4; assert_context(Context::RegExp.new("%r{", "}")); end
+ def test_reg5; assert_context(Context::RegExp.new("%r(", ")")); end
+ def test_reg6; assert_context(Context::RegExp.new("%r|", "|")); end
+
+ private
+
+ def assert_context(context)
+ octal = [*("0".."7")]
+ hex = [*("a".."f"), *("A".."F"), *("0".."9")]
+
+ (0...256).each do |ord|
+ # I think this might be a bug in Ruby.
+ next if context.name == "?" && ord == 0xFF
+
+ # We don't currently support scanning for the number of capture groups
+ # to validate backreferences so these are all going to fail.
+ next if (context.name == "//" || context.name.start_with?("%r")) && ord.chr.start_with?(/\d/)
+
+ # \u is passed directly on to the regular expression engine and it is
+ # responsible for handling syntax errors. In this case we do not check
+ # it because it would require going through the compiler.
+ next if context.is_a?(Context::RegExp) && ord.chr == "u"
+
+ # \a \b \c ...
+ assert_unescape(context, ord.chr)
+ end
+
+ # \\r\n
+ assert_unescape(context, "\r\n")
+
+ # We don't currently support scanning for the number of capture groups to
+ # validate backreferences so these are all going to fail.
+ if context.name != "//" && !context.name.start_with?("%r")
+ # \00 \01 \02 ...
+ octal.product(octal).each { |digits| assert_unescape(context, digits.join) }
+
+ # \000 \001 \002 ...
+ octal.product(octal).product(octal).each { |digits| assert_unescape(context, digits.join) }
+ end
+
+ # \x0 \x1 \x2 ...
+ hex.each { |digit| assert_unescape(context, "x#{digit}") }
+
+ # \x00 \x01 \x02 ...
+ hex.product(hex).each { |digits| assert_unescape(context, "x#{digits.join}") }
+
+ # \u0000 \u0001 \u0002 ...
+ assert_unescape(context, "u#{["5"].concat(hex.sample(3)).join}")
+
+ # The behavior of whitespace in the middle of these escape sequences
+ # changed in Ruby 3.3.0, so we only want to test against latest.
+ if RUBY_VERSION >= "3.3.0"
+ # \u{00 00} ...
+ assert_unescape(context, "u{00#{["5"].concat(hex.sample(3)).join} \t\v 00#{["5"].concat(hex.sample(3)).join}}")
+ end
+
+ (0...128).each do |ord|
+ chr = ord.chr
+ next if chr == "\\" || !chr.match?(/[[:print:]]/)
+
+ # \C-a \C-b \C-c ...
+ assert_unescape(context, "C-#{chr}")
+
+ # \C-\a \C-\b \C-\c ...
+ assert_unescape(context, "C-\\#{chr}")
+
+ # \ca \cb \cc ...
+ assert_unescape(context, "c#{chr}")
+
+ # \M-a \M-b \M-c ...
+ assert_unescape(context, "M-#{chr}")
+
+ # \M-\C-a \M-\C-b \M-\C-c ...
+ assert_unescape(context, "M-\\C-#{chr}")
+
+ # \M-\ca \M-\cb \M-\cc ...
+ assert_unescape(context, "M-\\c#{chr}")
+
+ # \c\M-a \c\M-b \c\M-c ...
+ assert_unescape(context, "c\\M-#{chr}")
+ end
+ end
+
+ def assert_unescape(context, escape)
+ expected = context.ruby_result(escape)
+ actual = context.prism_result(escape)
+
+ message = -> do
+ "Expected #{context.name} to unescape #{escape.inspect} to " \
+ "#{expected.inspect}, but got #{actual.inspect}"
+ end
+
+ if expected == :error || actual == :error
+ assert_equal expected, actual, message
+ else
+ assert_equal expected.bytes, actual.bytes, message
+ end
+ end
+ end
+end
diff --git a/test/prism/version_test.rb b/test/prism/version_test.rb
new file mode 100644
index 0000000000..149cfd62b4
--- /dev/null
+++ b/test/prism/version_test.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require_relative "test_helper"
+
+module Prism
+ class VersionTest < TestCase
+ def test_prism_version_is_set
+ refute_nil VERSION
+ end
+ end
+end