From e39427d18aac8a749fb8370598a61ecd6b337ec9 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Thu, 17 Jul 2025 09:59:26 -0400 Subject: [PATCH] Remove the translation layer The translation layer is now removed in favor of using the translation layer built into prism. --- bin/whitequark | 79 - doc/changing_structure.md | 16 - lib/syntax_tree.rb | 1 - lib/syntax_tree/translation.rb | 28 - lib/syntax_tree/translation/parser.rb | 3107 -------------------- lib/syntax_tree/translation/rubocop_ast.rb | 21 - tasks/whitequark.rake | 92 - test/translation/parser.txt | 1852 ------------ test/translation/parser_test.rb | 141 - 9 files changed, 5337 deletions(-) delete mode 100755 bin/whitequark delete mode 100644 doc/changing_structure.md delete mode 100644 lib/syntax_tree/translation.rb delete mode 100644 lib/syntax_tree/translation/parser.rb delete mode 100644 lib/syntax_tree/translation/rubocop_ast.rb delete mode 100644 tasks/whitequark.rake delete mode 100644 test/translation/parser.txt delete mode 100644 test/translation/parser_test.rb diff --git a/bin/whitequark b/bin/whitequark deleted file mode 100755 index 121bcd53..00000000 --- a/bin/whitequark +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -require "bundler/setup" -require "parser/current" - -$:.unshift(File.expand_path("../lib", __dir__)) -require "syntax_tree" - -# First, opt in to every AST feature. -Parser::Builders::Default.modernize - -# 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 - } -) - -source = ARGF.read - -parser = Parser::CurrentRuby.new -parser.diagnostics.all_errors_are_fatal = true - -buffer = Parser::Source::Buffer.new("(string)", 1) -buffer.source = source.dup.force_encoding(parser.default_encoding) - -stree = SyntaxTree::Translation.to_parser(SyntaxTree.parse(source), buffer) -ptree = parser.parse(buffer) - -if stree == ptree - puts "Syntax trees are equivalent." -elsif stree.inspect == ptree.inspect - warn "Syntax tree locations are different." - - queue = [[stree, ptree]] - while (left, right = queue.shift) - if left.location != right.location - warn "Different node:" - pp left - - warn "Different location:" - - warn "Syntax Tree:" - pp left.location - - warn "whitequark/parser:" - pp right.location - - exit - 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 -else - warn "Syntax Tree:" - pp stree - - warn "whitequark/parser:" - pp ptree -end diff --git a/doc/changing_structure.md b/doc/changing_structure.md deleted file mode 100644 index 74012f26..00000000 --- a/doc/changing_structure.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changing structure - -First and foremost, changing the structure of the tree in any way is a major breaking change. It forces the consumers to update their visitors, pattern matches, and method calls. It should not be taking lightly, and can only happen on a major version change. So keep that in mind. - -That said, if you do want to change the structure of the tree, there are a few steps that you have to take. They are enumerated below. - -1. Change the structure in the required node classes. This could mean adding/removing classes or adding/removing fields. Be sure to also update the `copy` and `===` methods to be sure that they are correct. -2. Update the parser to correctly create the new structure. -3. Update any visitor methods that are affected by the change. For example, if adding a new node make sure to create the new visit method alias in the `Visitor` class. -4. Update the `FieldVisitor` class to be sure that the various serializers, pretty printers, and matchers all get updated accordingly. -5. Update the `DSL` module to be sure that folks can correctly create nodes with the new structure. -6. Ensure the formatting of the code hasn't changed. This can mostly be done by running the tests, but if there's a corner case that we don't cover that is now exposed by your change be sure to add test cases. -7. Update the translation visitors to ensure we're still translating into other ASTs correctly. -8. Update the YARV compiler visitor to ensure we're still compiling correctly. -9. Make sure we aren't referencing the previous structure in any documentation or tests. -10. Be sure to update `CHANGELOG.md` with a description of the change that you made. diff --git a/lib/syntax_tree.rb b/lib/syntax_tree.rb index 6c595db5..2c824f71 100644 --- a/lib/syntax_tree.rb +++ b/lib/syntax_tree.rb @@ -34,7 +34,6 @@ module SyntaxTree autoload :Pattern, "syntax_tree/pattern" autoload :PrettyPrintVisitor, "syntax_tree/pretty_print_visitor" autoload :Search, "syntax_tree/search" - autoload :Translation, "syntax_tree/translation" autoload :WithScope, "syntax_tree/with_scope" autoload :YARV, "syntax_tree/yarv" diff --git a/lib/syntax_tree/translation.rb b/lib/syntax_tree/translation.rb deleted file mode 100644 index 6fc96f00..00000000 --- a/lib/syntax_tree/translation.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -module SyntaxTree - # This module is responsible for translating the Syntax Tree syntax tree into - # other representations. - module Translation - # This method translates the given node into the representation defined by - # the whitequark/parser gem. We don't explicitly list it as a dependency - # because it's not required for the core functionality of Syntax Tree. - def self.to_parser(node, buffer) - require "parser" - require_relative "translation/parser" - - node.accept(Parser.new(buffer)) - end - - # This method translates the given node into the representation defined by - # the rubocop/rubocop-ast gem. We don't explicitly list it as a dependency - # because it's not required for the core functionality of Syntax Tree. - def self.to_rubocop_ast(node, buffer) - require "rubocop/ast" - require_relative "translation/parser" - require_relative "translation/rubocop_ast" - - node.accept(RuboCopAST.new(buffer)) - end - end -end diff --git a/lib/syntax_tree/translation/parser.rb b/lib/syntax_tree/translation/parser.rb deleted file mode 100644 index 8be4fc79..00000000 --- a/lib/syntax_tree/translation/parser.rb +++ /dev/null @@ -1,3107 +0,0 @@ -# frozen_string_literal: true - -module SyntaxTree - module Translation - # This visitor is responsible for converting the syntax tree produced by - # Syntax Tree into the syntax tree produced by the whitequark/parser gem. - class Parser < BasicVisitor - # Heredocs are represented _very_ differently in the parser gem from how - # they are represented in the Syntax Tree AST. This class is responsible - # for handling the translation. - class HeredocBuilder - Line = Struct.new(:value, :segments) - - attr_reader :node, :segments - - def initialize(node) - @node = node - @segments = [] - end - - def <<(segment) - if segment.type == :str && segments.last && - segments.last.type == :str && - !segments.last.children.first.end_with?("\n") - segments.last.children.first << segment.children.first - else - segments << segment - end - end - - def trim! - return unless node.beginning.value[2] == "~" - lines = [Line.new(+"", [])] - - segments.each do |segment| - lines.last.segments << segment - - if segment.type == :str - lines.last.value << segment.children.first - lines << Line.new(+"", []) if lines.last.value.end_with?("\n") - end - end - - lines.pop if lines.last.value.empty? - return if lines.empty? - - segments.clear - lines.each do |line| - remaining = node.dedent - - line.segments.each do |segment| - if segment.type == :str - if remaining > 0 - whitespace = segment.children.first[/^\s{0,#{remaining}}/] - segment.children.first.sub!(/^#{whitespace}/, "") - remaining -= whitespace.length - end - - if node.beginning.value[3] != "'" && segments.any? && - segments.last.type == :str && - segments.last.children.first.end_with?("\\\n") - segments.last.children.first.gsub!(/\\\n\z/, "") - segments.last.children.first.concat(segment.children.first) - elsif !segment.children.first.empty? - segments << segment - end - else - segments << segment - end - end - end - end - end - - attr_reader :buffer, :stack - - def initialize(buffer) - @buffer = buffer - @stack = [] - end - - # For each node that we visit, we keep track of it in a stack as we - # descend into its children. We do this so that child nodes can reflect on - # their parents if they need additional information about their context. - def visit(node) - stack << node - result = super - stack.pop - result - end - - visit_methods do - # Visit an AliasNode node. - def visit_alias(node) - s( - :alias, - [visit(node.left), visit(node.right)], - smap_keyword_bare( - srange_length(node.start_char, 5), - srange_node(node) - ) - ) - end - - # Visit an ARefNode. - def visit_aref(node) - if ::Parser::Builders::Default.emit_index - if node.index.nil? - s( - :index, - [visit(node.collection)], - smap_index( - srange_find(node.collection.end_char, node.end_char, "["), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - else - s( - :index, - [visit(node.collection)].concat(visit_all(node.index.parts)), - smap_index( - srange_find_between(node.collection, node.index, "["), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - end - else - if node.index.nil? - s( - :send, - [visit(node.collection), :[]], - smap_send_bare( - srange_find(node.collection.end_char, node.end_char, "[]"), - srange_node(node) - ) - ) - else - s( - :send, - [visit(node.collection), :[], *visit_all(node.index.parts)], - smap_send_bare( - srange( - srange_find_between( - node.collection, - node.index, - "[" - ).begin_pos, - node.end_char - ), - srange_node(node) - ) - ) - end - end - end - - # Visit an ARefField node. - def visit_aref_field(node) - if ::Parser::Builders::Default.emit_index - if node.index.nil? - s( - :indexasgn, - [visit(node.collection)], - smap_index( - srange_find(node.collection.end_char, node.end_char, "["), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - else - s( - :indexasgn, - [visit(node.collection)].concat(visit_all(node.index.parts)), - smap_index( - srange_find_between(node.collection, node.index, "["), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - end - else - if node.index.nil? - s( - :send, - [visit(node.collection), :[]=], - smap_send_bare( - srange_find(node.collection.end_char, node.end_char, "[]"), - srange_node(node) - ) - ) - else - s( - :send, - [visit(node.collection), :[]=].concat( - visit_all(node.index.parts) - ), - smap_send_bare( - srange( - srange_find_between( - node.collection, - node.index, - "[" - ).begin_pos, - node.end_char - ), - srange_node(node) - ) - ) - end - end - end - - # Visit an ArgBlock node. - def visit_arg_block(node) - s( - :block_pass, - [visit(node.value)], - smap_operator(srange_length(node.start_char, 1), srange_node(node)) - ) - end - - # Visit an ArgStar node. - def visit_arg_star(node) - if stack[-3].is_a?(MLHSParen) && stack[-3].contents.is_a?(MLHS) - if node.value.nil? - s(:restarg, [], smap_variable(nil, srange_node(node))) - else - s( - :restarg, - [node.value.value.to_sym], - smap_variable(srange_node(node.value), srange_node(node)) - ) - end - else - s( - :splat, - node.value.nil? ? [] : [visit(node.value)], - smap_operator( - srange_length(node.start_char, 1), - srange_node(node) - ) - ) - end - end - - # Visit an ArgsForward node. - def visit_args_forward(node) - s(:forwarded_args, [], smap(srange_node(node))) - end - - # Visit an ArrayLiteral node. - def visit_array(node) - s( - :array, - node.contents ? visit_all(node.contents.parts) : [], - if node.lbracket.nil? - smap_collection_bare(srange_node(node)) - else - smap_collection( - srange_node(node.lbracket), - srange_length(node.end_char, -1), - srange_node(node) - ) - end - ) - end - - # Visit an AryPtn node. - def visit_aryptn(node) - type = :array_pattern - children = visit_all(node.requireds) - - if node.rest.is_a?(VarField) - if !node.rest.value.nil? - children << s(:match_rest, [visit(node.rest)], nil) - elsif node.posts.empty? && - node.rest.start_char == node.rest.end_char - # Here we have an implicit rest, as in [foo,]. parser has a - # specific type for these patterns. - type = :array_pattern_with_tail - else - children << s(:match_rest, [], nil) - end - end - - if node.constant - s( - :const_pattern, - [ - visit(node.constant), - s( - type, - children + visit_all(node.posts), - smap_collection_bare( - srange(node.constant.end_char + 1, node.end_char - 1) - ) - ) - ], - smap_collection( - srange_length(node.constant.end_char, 1), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - else - s( - type, - children + visit_all(node.posts), - if buffer.source[node.start_char] == "[" - smap_collection( - srange_length(node.start_char, 1), - srange_length(node.end_char, -1), - srange_node(node) - ) - else - smap_collection_bare(srange_node(node)) - end - ) - end - end - - # Visit an Assign node. - def visit_assign(node) - target = visit(node.target) - location = - target - .location - .with_operator(srange_find_between(node.target, node.value, "=")) - .with_expression(srange_node(node)) - - s(target.type, target.children + [visit(node.value)], location) - end - - # Visit an Assoc node. - def visit_assoc(node) - if node.value.nil? - # { foo: } - expression = srange(node.start_char, node.end_char - 1) - type, location = - if node.key.value.start_with?(/[A-Z]/) - [:const, smap_constant(nil, expression, expression)] - else - [:send, smap_send_bare(expression, expression)] - end - - s( - :pair, - [ - visit(node.key), - s(type, [nil, node.key.value.chomp(":").to_sym], location) - ], - smap_operator( - srange_length(node.key.end_char, -1), - srange_node(node) - ) - ) - elsif node.key.is_a?(Label) - # { foo: 1 } - s( - :pair, - [visit(node.key), visit(node.value)], - smap_operator( - srange_length(node.key.end_char, -1), - srange_node(node) - ) - ) - elsif (operator = srange_search_between(node.key, node.value, "=>")) - # { :foo => 1 } - s( - :pair, - [visit(node.key), visit(node.value)], - smap_operator(operator, srange_node(node)) - ) - else - # { "foo": 1 } - key = visit(node.key) - key_location = - smap_collection( - key.location.begin, - srange_length(node.key.end_char - 2, 1), - srange(node.key.start_char, node.key.end_char - 1) - ) - - s( - :pair, - [s(key.type, key.children, key_location), visit(node.value)], - smap_operator( - srange_length(node.key.end_char, -1), - srange_node(node) - ) - ) - end - end - - # Visit an AssocSplat node. - def visit_assoc_splat(node) - s( - :kwsplat, - [visit(node.value)], - smap_operator(srange_length(node.start_char, 2), srange_node(node)) - ) - end - - # Visit a Backref node. - def visit_backref(node) - location = smap(srange_node(node)) - - if node.value.match?(/^\$\d+$/) - s(:nth_ref, [node.value[1..].to_i], location) - else - s(:back_ref, [node.value.to_sym], location) - end - end - - # Visit a BareAssocHash node. - def visit_bare_assoc_hash(node) - s( - if ::Parser::Builders::Default.emit_kwargs && - !stack[-2].is_a?(ArrayLiteral) - :kwargs - else - :hash - end, - visit_all(node.assocs), - smap_collection_bare(srange_node(node)) - ) - end - - # Visit a BEGINBlock node. - def visit_BEGIN(node) - s( - :preexe, - [visit(node.statements)], - smap_keyword( - srange_length(node.start_char, 5), - srange_find(node.start_char + 5, node.statements.start_char, "{"), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - end - - # Visit a Begin node. - def visit_begin(node) - location = - smap_collection( - srange_length(node.start_char, 5), - srange_length(node.end_char, -3), - srange_node(node) - ) - - if node.bodystmt.empty? - s(:kwbegin, [], location) - elsif node.bodystmt.rescue_clause.nil? && - node.bodystmt.ensure_clause.nil? && - node.bodystmt.else_clause.nil? - child = visit(node.bodystmt.statements) - - s( - :kwbegin, - child.type == :begin ? child.children : [child], - location - ) - else - s(:kwbegin, [visit(node.bodystmt)], location) - end - end - - # Visit a Binary node. - def visit_binary(node) - case node.operator - when :| - current = -2 - while stack[current].is_a?(Binary) && stack[current].operator == :| - current -= 1 - end - - if stack[current].is_a?(In) - s(:match_alt, [visit(node.left), visit(node.right)], nil) - else - visit(canonical_binary(node)) - end - when :"=>", :"&&", :and, :"||", :or - s( - { "=>": :match_as, "&&": :and, "||": :or }.fetch( - node.operator, - node.operator - ), - [visit(node.left), visit(node.right)], - smap_operator( - srange_find_between(node.left, node.right, node.operator.to_s), - srange_node(node) - ) - ) - when :=~ - # When you use a regular expression on the left hand side of a =~ - # operator and it doesn't have interpolatoin, then its named capture - # groups introduce local variables into the scope. In this case the - # parser gem has a different node (match_with_lvasgn) instead of the - # regular send. - if node.left.is_a?(RegexpLiteral) && node.left.parts.length == 1 && - node.left.parts.first.is_a?(TStringContent) - s( - :match_with_lvasgn, - [visit(node.left), visit(node.right)], - smap_operator( - srange_find_between( - node.left, - node.right, - node.operator.to_s - ), - srange_node(node) - ) - ) - else - visit(canonical_binary(node)) - end - else - visit(canonical_binary(node)) - end - end - - # Visit a BlockArg node. - def visit_blockarg(node) - if node.name.nil? - s(:blockarg, [nil], smap_variable(nil, srange_node(node))) - else - s( - :blockarg, - [node.name.value.to_sym], - smap_variable(srange_node(node.name), srange_node(node)) - ) - end - end - - # Visit a BlockVar node. - def visit_block_var(node) - shadowargs = - node.locals.map do |local| - s( - :shadowarg, - [local.value.to_sym], - smap_variable(srange_node(local), srange_node(local)) - ) - end - - params = node.params - children = - if ::Parser::Builders::Default.emit_procarg0 && node.arg0? - # There is a special node type in the parser gem for when a single - # required parameter to a block would potentially be expanded - # automatically. We handle that case here. - required = params.requireds.first - procarg0 = - if ::Parser::Builders::Default.emit_arg_inside_procarg0 && - required.is_a?(Ident) - s( - :procarg0, - [ - s( - :arg, - [required.value.to_sym], - smap_variable( - srange_node(required), - srange_node(required) - ) - ) - ], - smap_collection_bare(srange_node(required)) - ) - else - child = visit(required) - s(:procarg0, child, child.location) - end - - [procarg0] - else - visit(params).children - end - - s( - :args, - children + shadowargs, - smap_collection( - srange_length(node.start_char, 1), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - end - - # Visit a BodyStmt node. - def visit_bodystmt(node) - result = visit(node.statements) - - if node.rescue_clause - rescue_node = visit(node.rescue_clause) - - children = [result] + rescue_node.children - location = rescue_node.location - - if node.else_clause - children.pop - children << visit(node.else_clause) - - location = - smap_condition( - nil, - nil, - srange_length(node.else_clause.start_char - 3, -4), - nil, - srange( - location.expression.begin_pos, - node.else_clause.end_char - ) - ) - end - - result = s(rescue_node.type, children, location) - end - - if node.ensure_clause - ensure_node = visit(node.ensure_clause) - - expression = - ( - if result - result.location.expression.join( - ensure_node.location.expression - ) - else - ensure_node.location.expression - end - ) - location = ensure_node.location.with_expression(expression) - - result = - s(ensure_node.type, [result] + ensure_node.children, location) - end - - result - end - - # Visit a Break node. - def visit_break(node) - s( - :break, - visit_all(node.arguments.parts), - smap_keyword_bare( - srange_length(node.start_char, 5), - srange_node(node) - ) - ) - end - - # Visit a CallNode node. - def visit_call(node) - visit_command_call( - CommandCall.new( - receiver: node.receiver, - operator: node.operator, - message: node.message, - arguments: node.arguments, - block: nil, - location: node.location - ) - ) - end - - # Visit a Case node. - def visit_case(node) - clauses = [node.consequent] - while clauses.last && !clauses.last.is_a?(Else) - clauses << clauses.last.consequent - end - - else_token = - if clauses.last.is_a?(Else) - srange_length(clauses.last.start_char, 4) - end - - s( - node.consequent.is_a?(In) ? :case_match : :case, - [visit(node.value)] + clauses.map { |clause| visit(clause) }, - smap_condition( - srange_length(node.start_char, 4), - nil, - else_token, - srange_length(node.end_char, -3), - srange_node(node) - ) - ) - end - - # Visit a CHAR node. - def visit_CHAR(node) - s( - :str, - [node.value[1..]], - smap_collection( - srange_length(node.start_char, 1), - nil, - srange_node(node) - ) - ) - end - - # Visit a ClassDeclaration node. - def visit_class(node) - operator = - if node.superclass - srange_find_between(node.constant, node.superclass, "<") - end - - s( - :class, - [ - visit(node.constant), - visit(node.superclass), - visit(node.bodystmt) - ], - smap_definition( - srange_length(node.start_char, 5), - operator, - srange_node(node.constant), - srange_length(node.end_char, -3) - ).with_expression(srange_node(node)) - ) - end - - # Visit a Command node. - def visit_command(node) - visit_command_call( - CommandCall.new( - receiver: nil, - operator: nil, - message: node.message, - arguments: node.arguments, - block: node.block, - location: node.location - ) - ) - end - - # Visit a CommandCall node. - def visit_command_call(node) - children = [ - visit(node.receiver), - node.message == :call ? :call : node.message.value.to_sym - ] - - begin_token = nil - end_token = nil - - case node.arguments - when Args - children += visit_all(node.arguments.parts) - when ArgParen - case node.arguments.arguments - when nil - # skip - when ArgsForward - children << visit(node.arguments.arguments) - else - children += visit_all(node.arguments.arguments.parts) - end - - begin_token = srange_length(node.arguments.start_char, 1) - end_token = srange_length(node.arguments.end_char, -1) - end - - dot_bound = - if node.arguments - node.arguments.start_char - elsif node.block - node.block.start_char - else - node.end_char - end - - expression = - if node.arguments.is_a?(ArgParen) - srange(node.start_char, node.arguments.end_char) - elsif node.arguments.is_a?(Args) && node.arguments.parts.any? - last_part = node.arguments.parts.last - end_char = - if last_part.is_a?(Heredoc) - last_part.beginning.end_char - else - last_part.end_char - end - - srange(node.start_char, end_char) - elsif node.block - if node.receiver - srange(node.receiver.start_char, node.message.end_char) - else - srange_node(node.message) - end - else - srange_node(node) - end - - call = - s( - if node.operator.is_a?(Op) && node.operator.value == "&." - :csend - else - :send - end, - children, - smap_send( - if node.operator == :"::" - srange_find( - node.receiver.end_char, - if node.message == :call - dot_bound - else - node.message.start_char - end, - "::" - ) - elsif node.operator - srange_node(node.operator) - end, - node.message == :call ? nil : srange_node(node.message), - begin_token, - end_token, - expression - ) - ) - - if node.block - type, arguments = block_children(node.block) - - s( - type, - [call, arguments, visit(node.block.bodystmt)], - smap_collection( - srange_node(node.block.opening), - srange_length( - node.end_char, - node.block.opening.is_a?(Kw) ? -3 : -1 - ), - srange_node(node) - ) - ) - else - call - end - end - - # Visit a Const node. - def visit_const(node) - s( - :const, - [nil, node.value.to_sym], - smap_constant(nil, srange_node(node), srange_node(node)) - ) - end - - # Visit a ConstPathField node. - def visit_const_path_field(node) - if node.parent.is_a?(VarRef) && node.parent.value.is_a?(Kw) && - node.parent.value.value == "self" && node.constant.is_a?(Ident) - s(:send, [visit(node.parent), :"#{node.constant.value}="], nil) - else - s( - :casgn, - [visit(node.parent), node.constant.value.to_sym], - smap_constant( - srange_find_between(node.parent, node.constant, "::"), - srange_node(node.constant), - srange_node(node) - ) - ) - end - end - - # Visit a ConstPathRef node. - def visit_const_path_ref(node) - s( - :const, - [visit(node.parent), node.constant.value.to_sym], - smap_constant( - srange_find_between(node.parent, node.constant, "::"), - srange_node(node.constant), - srange_node(node) - ) - ) - end - - # Visit a ConstRef node. - def visit_const_ref(node) - s( - :const, - [nil, node.constant.value.to_sym], - smap_constant(nil, srange_node(node.constant), srange_node(node)) - ) - end - - # Visit a CVar node. - def visit_cvar(node) - s( - :cvar, - [node.value.to_sym], - smap_variable(srange_node(node), srange_node(node)) - ) - end - - # Visit a DefNode node. - def visit_def(node) - name = node.name.value.to_sym - args = - case node.params - when Params - child = visit(node.params) - - s( - child.type, - child.children, - smap_collection_bare(child.location&.expression) - ) - when Paren - child = visit(node.params.contents) - - s( - child.type, - child.children, - smap_collection( - srange_length(node.params.start_char, 1), - srange_length(node.params.end_char, -1), - srange_node(node.params) - ) - ) - else - s(:args, [], smap_collection_bare(nil)) - end - - location = - if node.endless? - smap_method_definition( - srange_length(node.start_char, 3), - nil, - srange_node(node.name), - nil, - srange_find_between( - (node.params || node.name), - node.bodystmt, - "=" - ), - srange_node(node) - ) - else - smap_method_definition( - srange_length(node.start_char, 3), - nil, - srange_node(node.name), - srange_length(node.end_char, -3), - nil, - srange_node(node) - ) - end - - if node.target - target = - node.target.is_a?(Paren) ? node.target.contents : node.target - - s( - :defs, - [visit(target), name, args, visit(node.bodystmt)], - smap_method_definition( - location.keyword, - srange_node(node.operator), - location.name, - location.end, - location.assignment, - location.expression - ) - ) - else - s(:def, [name, args, visit(node.bodystmt)], location) - end - end - - # Visit a Defined node. - def visit_defined(node) - paren_range = (node.start_char + 8)...node.end_char - begin_token, end_token = - if buffer.source[paren_range].include?("(") - [ - srange_find(paren_range.begin, paren_range.end, "("), - srange_length(node.end_char, -1) - ] - end - - s( - :defined?, - [visit(node.value)], - smap_keyword( - srange_length(node.start_char, 8), - begin_token, - end_token, - srange_node(node) - ) - ) - end - - # Visit a DynaSymbol node. - def visit_dyna_symbol(node) - location = - if node.quote - smap_collection( - srange_length(node.start_char, node.quote.length), - srange_length(node.end_char, -1), - srange_node(node) - ) - else - smap_collection_bare(srange_node(node)) - end - - if node.parts.length == 1 && node.parts.first.is_a?(TStringContent) - s(:sym, ["\"#{node.parts.first.value}\"".undump.to_sym], location) - else - s(:dsym, visit_all(node.parts), location) - end - end - - # Visit an Else node. - def visit_else(node) - if node.statements.empty? && stack[-2].is_a?(Case) - s(:empty_else, [], nil) - else - visit(node.statements) - end - end - - # Visit an Elsif node. - def visit_elsif(node) - begin_start = node.predicate.end_char - begin_end = - if node.statements.empty? - node.statements.end_char - else - node.statements.body.first.start_char - end - - begin_token = - if buffer.source[begin_start...begin_end].include?("then") - srange_find(begin_start, begin_end, "then") - elsif buffer.source[begin_start...begin_end].include?(";") - srange_find(begin_start, begin_end, ";") - end - - else_token = - case node.consequent - when Elsif - srange_length(node.consequent.start_char, 5) - when Else - srange_length(node.consequent.start_char, 4) - end - - expression = srange(node.start_char, node.statements.end_char - 1) - - s( - :if, - [ - visit(node.predicate), - visit(node.statements), - visit(node.consequent) - ], - smap_condition( - srange_length(node.start_char, 5), - begin_token, - else_token, - nil, - expression - ) - ) - end - - # Visit an ENDBlock node. - def visit_END(node) - s( - :postexe, - [visit(node.statements)], - smap_keyword( - srange_length(node.start_char, 3), - srange_find(node.start_char + 3, node.statements.start_char, "{"), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - end - - # Visit an Ensure node. - def visit_ensure(node) - start_char = node.start_char - end_char = - if node.statements.empty? - start_char + 6 - else - node.statements.body.last.end_char - end - - s( - :ensure, - [visit(node.statements)], - smap_condition( - srange_length(start_char, 6), - nil, - nil, - nil, - srange(start_char, end_char) - ) - ) - end - - # Visit a Field node. - def visit_field(node) - message = - case stack[-2] - when Assign, MLHS - Ident.new( - value: "#{node.name.value}=", - location: node.name.location - ) - else - node.name - end - - visit_command_call( - CommandCall.new( - receiver: node.parent, - operator: node.operator, - message: message, - arguments: nil, - block: nil, - location: node.location - ) - ) - end - - # Visit a FloatLiteral node. - def visit_float(node) - operator = - if %w[+ -].include?(buffer.source[node.start_char]) - srange_length(node.start_char, 1) - end - - s( - :float, - [node.value.to_f], - smap_operator(operator, srange_node(node)) - ) - end - - # Visit a FndPtn node. - def visit_fndptn(node) - left, right = - [node.left, node.right].map do |child| - location = - smap_operator( - srange_length(child.start_char, 1), - srange_node(child) - ) - - if child.is_a?(VarField) && child.value.nil? - s(:match_rest, [], location) - else - s(:match_rest, [visit(child)], location) - end - end - - inner = - s( - :find_pattern, - [left, *visit_all(node.values), right], - smap_collection( - srange_length(node.start_char, 1), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - - if node.constant - s(:const_pattern, [visit(node.constant), inner], nil) - else - inner - end - end - - # Visit a For node. - def visit_for(node) - s( - :for, - [visit(node.index), visit(node.collection), visit(node.statements)], - smap_for( - srange_length(node.start_char, 3), - srange_find_between(node.index, node.collection, "in"), - srange_search_between(node.collection, node.statements, "do") || - srange_search_between(node.collection, node.statements, ";"), - srange_length(node.end_char, -3), - srange_node(node) - ) - ) - end - - # Visit a GVar node. - def visit_gvar(node) - s( - :gvar, - [node.value.to_sym], - smap_variable(srange_node(node), srange_node(node)) - ) - end - - # Visit a HashLiteral node. - def visit_hash(node) - s( - :hash, - visit_all(node.assocs), - smap_collection( - srange_length(node.start_char, 1), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - end - - # Visit a Heredoc node. - def visit_heredoc(node) - heredoc = HeredocBuilder.new(node) - - # For each part of the heredoc, if it's a string content node, split - # it into multiple string content nodes, one for each line. Otherwise, - # visit the node as normal. - node.parts.each do |part| - if part.is_a?(TStringContent) && part.value.count("\n") > 1 - index = part.start_char - lines = part.value.split("\n") - - lines.each do |line| - length = line.length + 1 - location = smap_collection_bare(srange_length(index, length)) - - heredoc << s(:str, ["#{line}\n"], location) - index += length - end - else - heredoc << visit(part) - end - end - - # Now that we have all of the pieces on the heredoc, we can trim it if - # it is a heredoc that supports trimming (i.e., it has a ~ on the - # declaration). - heredoc.trim! - - # Generate the location for the heredoc, which goes from the - # declaration to the ending delimiter. - location = - smap_heredoc( - srange_node(node.beginning), - srange( - if node.parts.empty? - node.beginning.end_char + 1 - else - node.parts.first.start_char - end, - node.ending.start_char - ), - srange(node.ending.start_char, node.ending.end_char - 1) - ) - - # Finally, decide which kind of heredoc node to generate based on its - # declaration and contents. - if node.beginning.value.match?(/`\w+`\z/) - s(:xstr, heredoc.segments, location) - elsif heredoc.segments.length == 1 - segment = heredoc.segments.first - s(segment.type, segment.children, location) - else - s(:dstr, heredoc.segments, location) - end - end - - # Visit a HshPtn node. - def visit_hshptn(node) - children = - node.keywords.map do |(keyword, value)| - next s(:pair, [visit(keyword), visit(value)], nil) if value - - case keyword - when DynaSymbol - raise if keyword.parts.length > 1 - s(:match_var, [keyword.parts.first.value.to_sym], nil) - when Label - s(:match_var, [keyword.value.chomp(":").to_sym], nil) - end - end - - if node.keyword_rest.is_a?(VarField) - children << if node.keyword_rest.value.nil? - s(:match_rest, [], nil) - elsif node.keyword_rest.value == :nil - s(:match_nil_pattern, [], nil) - else - s(:match_rest, [visit(node.keyword_rest)], nil) - end - end - - inner = s(:hash_pattern, children, nil) - if node.constant - s(:const_pattern, [visit(node.constant), inner], nil) - else - inner - end - end - - # Visit an Ident node. - def visit_ident(node) - s( - :lvar, - [node.value.to_sym], - smap_variable(srange_node(node), srange_node(node)) - ) - end - - # Visit an IfNode node. - def visit_if(node) - s( - :if, - [ - visit_predicate(node.predicate), - visit(node.statements), - visit(node.consequent) - ], - if node.modifier? - smap_keyword_bare( - srange_find_between(node.statements, node.predicate, "if"), - srange_node(node) - ) - else - begin_start = node.predicate.end_char - begin_end = - if node.statements.empty? - node.statements.end_char - else - node.statements.body.first.start_char - end - - begin_token = - if buffer.source[begin_start...begin_end].include?("then") - srange_find(begin_start, begin_end, "then") - elsif buffer.source[begin_start...begin_end].include?(";") - srange_find(begin_start, begin_end, ";") - end - - else_token = - case node.consequent - when Elsif - srange_length(node.consequent.start_char, 5) - when Else - srange_length(node.consequent.start_char, 4) - end - - smap_condition( - srange_length(node.start_char, 2), - begin_token, - else_token, - srange_length(node.end_char, -3), - srange_node(node) - ) - end - ) - end - - # Visit an IfOp node. - def visit_if_op(node) - s( - :if, - [visit(node.predicate), visit(node.truthy), visit(node.falsy)], - smap_ternary( - srange_find_between(node.predicate, node.truthy, "?"), - srange_find_between(node.truthy, node.falsy, ":"), - srange_node(node) - ) - ) - end - - # Visit an Imaginary node. - def visit_imaginary(node) - s( - :complex, - [ - # We have to do an eval here in order to get the value in case - # it's something like 42ri. to_c will not give the right value in - # that case. Maybe there's an API for this but I can't find it. - eval(node.value) - ], - smap_operator(nil, srange_node(node)) - ) - end - - # Visit an In node. - def visit_in(node) - case node.pattern - when IfNode - s( - :in_pattern, - [ - visit(node.pattern.statements), - s(:if_guard, [visit(node.pattern.predicate)], nil), - visit(node.statements) - ], - nil - ) - when UnlessNode - s( - :in_pattern, - [ - visit(node.pattern.statements), - s(:unless_guard, [visit(node.pattern.predicate)], nil), - visit(node.statements) - ], - nil - ) - else - begin_token = - srange_search_between(node.pattern, node.statements, "then") - - end_char = - if begin_token || node.statements.empty? - node.statements.end_char - 1 - else - node.statements.body.last.start_char - end - - s( - :in_pattern, - [visit(node.pattern), nil, visit(node.statements)], - smap_keyword( - srange_length(node.start_char, 2), - begin_token, - nil, - srange(node.start_char, end_char) - ) - ) - end - end - - # Visit an Int node. - def visit_int(node) - operator = - if %w[+ -].include?(buffer.source[node.start_char]) - srange_length(node.start_char, 1) - end - - s(:int, [node.value.to_i], smap_operator(operator, srange_node(node))) - end - - # Visit an IVar node. - def visit_ivar(node) - s( - :ivar, - [node.value.to_sym], - smap_variable(srange_node(node), srange_node(node)) - ) - end - - # Visit a Kw node. - def visit_kw(node) - location = smap(srange_node(node)) - - case node.value - when "__FILE__" - s(:str, [buffer.name], location) - when "__LINE__" - s( - :int, - [node.location.start_line + buffer.first_line - 1], - location - ) - when "__ENCODING__" - if ::Parser::Builders::Default.emit_encoding - s(:__ENCODING__, [], location) - else - s(:const, [s(:const, [nil, :Encoding], nil), :UTF_8], location) - end - else - s(node.value.to_sym, [], location) - end - end - - # Visit a KwRestParam node. - def visit_kwrest_param(node) - if node.name.nil? - s(:kwrestarg, [], smap_variable(nil, srange_node(node))) - else - s( - :kwrestarg, - [node.name.value.to_sym], - smap_variable(srange_node(node.name), srange_node(node)) - ) - end - end - - # Visit a Label node. - def visit_label(node) - s( - :sym, - [node.value.chomp(":").to_sym], - smap_collection_bare(srange(node.start_char, node.end_char - 1)) - ) - end - - # Visit a Lambda node. - def visit_lambda(node) - args = - node.params.is_a?(LambdaVar) ? node.params : node.params.contents - args_node = visit(args) - - type = :block - if args.empty? && (maximum = num_block_type(node.statements)) - type = :numblock - args_node = maximum - end - - begin_token, end_token = - if ( - srange = - srange_search_between(node.params, node.statements, "{") - ) - [srange, srange_length(node.end_char, -1)] - else - [ - srange_find_between(node.params, node.statements, "do"), - srange_length(node.end_char, -3) - ] - end - - selector = srange_length(node.start_char, 2) - - s( - type, - [ - if ::Parser::Builders::Default.emit_lambda - s(:lambda, [], smap(selector)) - else - s(:send, [nil, :lambda], smap_send_bare(selector, selector)) - end, - args_node, - visit(node.statements) - ], - smap_collection(begin_token, end_token, srange_node(node)) - ) - end - - # Visit a LambdaVar node. - def visit_lambda_var(node) - shadowargs = - node.locals.map do |local| - s( - :shadowarg, - [local.value.to_sym], - smap_variable(srange_node(local), srange_node(local)) - ) - end - - location = - if node.start_char == node.end_char - smap_collection_bare(nil) - elsif buffer.source[node.start_char - 1] == "(" - smap_collection( - srange_length(node.start_char, 1), - srange_length(node.end_char, -1), - srange_node(node) - ) - else - smap_collection_bare(srange_node(node)) - end - - s(:args, visit(node.params).children + shadowargs, location) - end - - # Visit an MAssign node. - def visit_massign(node) - s( - :masgn, - [visit(node.target), visit(node.value)], - smap_operator( - srange_find_between(node.target, node.value, "="), - srange_node(node) - ) - ) - end - - # Visit a MethodAddBlock node. - def visit_method_add_block(node) - case node.call - when ARef, Super, ZSuper - type, arguments = block_children(node.block) - - s( - type, - [visit(node.call), arguments, visit(node.block.bodystmt)], - smap_collection( - srange_node(node.block.opening), - srange_length( - node.block.end_char, - node.block.keywords? ? -3 : -1 - ), - srange_node(node) - ) - ) - else - visit_command_call( - CommandCall.new( - receiver: node.call.receiver, - operator: node.call.operator, - message: node.call.message, - arguments: node.call.arguments, - block: node.block, - location: node.location - ) - ) - end - end - - # Visit an MLHS node. - def visit_mlhs(node) - s( - :mlhs, - node.parts.map do |part| - if part.is_a?(Ident) - s( - :arg, - [part.value.to_sym], - smap_variable(srange_node(part), srange_node(part)) - ) - else - visit(part) - end - end, - smap_collection_bare(srange_node(node)) - ) - end - - # Visit an MLHSParen node. - def visit_mlhs_paren(node) - child = visit(node.contents) - - s( - child.type, - child.children, - smap_collection( - srange_length(node.start_char, 1), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - end - - # Visit a ModuleDeclaration node. - def visit_module(node) - s( - :module, - [visit(node.constant), visit(node.bodystmt)], - smap_definition( - srange_length(node.start_char, 6), - nil, - srange_node(node.constant), - srange_length(node.end_char, -3) - ).with_expression(srange_node(node)) - ) - end - - # Visit an MRHS node. - def visit_mrhs(node) - visit_array( - ArrayLiteral.new( - lbracket: nil, - contents: Args.new(parts: node.parts, location: node.location), - location: node.location - ) - ) - end - - # Visit a Next node. - def visit_next(node) - s( - :next, - visit_all(node.arguments.parts), - smap_keyword_bare( - srange_length(node.start_char, 4), - srange_node(node) - ) - ) - end - - # Visit a Not node. - def visit_not(node) - if node.statement.nil? - begin_token = srange_find(node.start_char, nil, "(") - end_token = srange_find(node.start_char, nil, ")") - - s( - :send, - [ - s( - :begin, - [], - smap_collection( - begin_token, - end_token, - begin_token.join(end_token) - ) - ), - :! - ], - smap_send_bare( - srange_length(node.start_char, 3), - srange_node(node) - ) - ) - else - begin_token, end_token = - if node.parentheses? - [ - srange_find( - node.start_char + 3, - node.statement.start_char, - "(" - ), - srange_length(node.end_char, -1) - ] - end - - s( - :send, - [visit(node.statement), :!], - smap_send( - nil, - srange_length(node.start_char, 3), - begin_token, - end_token, - srange_node(node) - ) - ) - end - end - - # Visit an OpAssign node. - def visit_opassign(node) - target = visit(node.target) - location = - target - .location - .with_expression(srange_node(node)) - .with_operator(srange_node(node.operator)) - - case node.operator.value - when "||=" - s(:or_asgn, [target, visit(node.value)], location) - when "&&=" - s(:and_asgn, [target, visit(node.value)], location) - else - s( - :op_asgn, - [ - target, - node.operator.value.chomp("=").to_sym, - visit(node.value) - ], - location - ) - end - end - - # Visit a Params node. - def visit_params(node) - children = [] - - children += - node.requireds.map do |required| - case required - when MLHSParen - visit(required) - else - s( - :arg, - [required.value.to_sym], - smap_variable(srange_node(required), srange_node(required)) - ) - end - end - - children += - node.optionals.map do |(name, value)| - s( - :optarg, - [name.value.to_sym, visit(value)], - smap_variable( - srange_node(name), - srange_node(name).join(srange_node(value)) - ).with_operator(srange_find_between(name, value, "=")) - ) - end - - if node.rest && !node.rest.is_a?(ExcessedComma) - children << visit(node.rest) - end - - children += - node.posts.map do |post| - s( - :arg, - [post.value.to_sym], - smap_variable(srange_node(post), srange_node(post)) - ) - end - - children += - node.keywords.map do |(name, value)| - key = name.value.chomp(":").to_sym - - if value - s( - :kwoptarg, - [key, visit(value)], - smap_variable( - srange(name.start_char, name.end_char - 1), - srange_node(name).join(srange_node(value)) - ) - ) - else - s( - :kwarg, - [key], - smap_variable( - srange(name.start_char, name.end_char - 1), - srange_node(name) - ) - ) - end - end - - case node.keyword_rest - when nil, ArgsForward - # do nothing - when :nil - children << s( - :kwnilarg, - [], - smap_variable(srange_length(node.end_char, -3), srange_node(node)) - ) - else - children << visit(node.keyword_rest) - end - - children << visit(node.block) if node.block - - if node.keyword_rest.is_a?(ArgsForward) - location = smap(srange_node(node.keyword_rest)) - - # If there are no other arguments and we have the emit_forward_arg - # option enabled, then the entire argument list is represented by a - # single forward_args node. - if children.empty? && !::Parser::Builders::Default.emit_forward_arg - return s(:forward_args, [], location) - end - - # Otherwise, we need to insert a forward_arg node into the list of - # parameters before any keyword rest or block parameters. - index = - node.requireds.length + node.optionals.length + - node.keywords.length - children.insert(index, s(:forward_arg, [], location)) - end - - location = - unless children.empty? - first = children.first.location.expression - last = children.last.location.expression - smap_collection_bare(first.join(last)) - end - - s(:args, children, location) - end - - # Visit a Paren node. - def visit_paren(node) - location = - smap_collection( - srange_length(node.start_char, 1), - srange_length(node.end_char, -1), - srange_node(node) - ) - - if node.contents.nil? || - (node.contents.is_a?(Statements) && node.contents.empty?) - s(:begin, [], location) - else - child = visit(node.contents) - child.type == :begin ? child : s(:begin, [child], location) - end - end - - # Visit a PinnedBegin node. - def visit_pinned_begin(node) - s( - :pin, - [ - s( - :begin, - [visit(node.statement)], - smap_collection( - srange_length(node.start_char + 1, 1), - srange_length(node.end_char, -1), - srange(node.start_char + 1, node.end_char) - ) - ) - ], - smap_send_bare(srange_length(node.start_char, 1), srange_node(node)) - ) - end - - # Visit a PinnedVarRef node. - def visit_pinned_var_ref(node) - s( - :pin, - [visit(node.value)], - smap_send_bare(srange_length(node.start_char, 1), srange_node(node)) - ) - end - - # Visit a Program node. - def visit_program(node) - visit(node.statements) - end - - # Visit a QSymbols node. - def visit_qsymbols(node) - parts = - node.elements.map do |element| - SymbolLiteral.new(value: element, location: element.location) - end - - visit_array( - ArrayLiteral.new( - lbracket: node.beginning, - contents: Args.new(parts: parts, location: node.location), - location: node.location - ) - ) - end - - # Visit a QWords node. - def visit_qwords(node) - visit_array( - ArrayLiteral.new( - lbracket: node.beginning, - contents: Args.new(parts: node.elements, location: node.location), - location: node.location - ) - ) - end - - # Visit a RangeNode node. - def visit_range(node) - s( - node.operator.value == ".." ? :irange : :erange, - [visit(node.left), visit(node.right)], - smap_operator(srange_node(node.operator), srange_node(node)) - ) - end - - # Visit an RAssign node. - def visit_rassign(node) - s( - node.operator.value == "=>" ? :match_pattern : :match_pattern_p, - [visit(node.value), visit(node.pattern)], - smap_operator(srange_node(node.operator), srange_node(node)) - ) - end - - # Visit a Rational node. - def visit_rational(node) - s(:rational, [node.value.to_r], smap_operator(nil, srange_node(node))) - end - - # Visit a Redo node. - def visit_redo(node) - s(:redo, [], smap_keyword_bare(srange_node(node), srange_node(node))) - end - - # Visit a RegexpLiteral node. - def visit_regexp_literal(node) - s( - :regexp, - visit_all(node.parts).push( - s( - :regopt, - node.ending.scan(/[a-z]/).sort.map(&:to_sym), - smap(srange_length(node.end_char, -(node.ending.length - 1))) - ) - ), - smap_collection( - srange_length(node.start_char, node.beginning.length), - srange_length(node.end_char - node.ending.length, 1), - srange_node(node) - ) - ) - end - - # Visit a Rescue node. - def visit_rescue(node) - # In the parser gem, there is a separation between the rescue node and - # the rescue body. They have different bounds, so we have to calculate - # those here. - start_char = node.start_char - - body_end_char = - if node.statements.empty? - start_char + 6 - else - node.statements.body.last.end_char - end - - end_char = - if node.consequent - end_node = node.consequent - end_node = end_node.consequent while end_node.consequent - - if end_node.statements.empty? - start_char + 6 - else - end_node.statements.body.last.end_char - end - else - body_end_char - end - - # These locations are reused for multiple children. - keyword = srange_length(start_char, 6) - body_expression = srange(start_char, body_end_char) - expression = srange(start_char, end_char) - - exceptions = - case node.exception&.exceptions - when nil - nil - when MRHS - visit_array( - ArrayLiteral.new( - lbracket: nil, - contents: - Args.new( - parts: node.exception.exceptions.parts, - location: node.exception.exceptions.location - ), - location: node.exception.exceptions.location - ) - ) - else - visit_array( - ArrayLiteral.new( - lbracket: nil, - contents: - Args.new( - parts: [node.exception.exceptions], - location: node.exception.exceptions.location - ), - location: node.exception.exceptions.location - ) - ) - end - - resbody = - if node.exception.nil? - s( - :resbody, - [nil, nil, visit(node.statements)], - smap_rescue_body(keyword, nil, nil, body_expression) - ) - elsif node.exception.variable.nil? - s( - :resbody, - [exceptions, nil, visit(node.statements)], - smap_rescue_body(keyword, nil, nil, body_expression) - ) - else - s( - :resbody, - [ - exceptions, - visit(node.exception.variable), - visit(node.statements) - ], - smap_rescue_body( - keyword, - srange_find( - node.start_char + 6, - node.exception.variable.start_char, - "=>" - ), - nil, - body_expression - ) - ) - end - - children = [resbody] - if node.consequent - children += visit(node.consequent).children - else - children << nil - end - - s(:rescue, children, smap_condition_bare(expression)) - end - - # Visit a RescueMod node. - def visit_rescue_mod(node) - keyword = srange_find_between(node.statement, node.value, "rescue") - - s( - :rescue, - [ - visit(node.statement), - s( - :resbody, - [nil, nil, visit(node.value)], - smap_rescue_body( - keyword, - nil, - nil, - keyword.join(srange_node(node.value)) - ) - ), - nil - ], - smap_condition_bare(srange_node(node)) - ) - end - - # Visit a RestParam node. - def visit_rest_param(node) - if node.name - s( - :restarg, - [node.name.value.to_sym], - smap_variable(srange_node(node.name), srange_node(node)) - ) - else - s(:restarg, [], smap_variable(nil, srange_node(node))) - end - end - - # Visit a Retry node. - def visit_retry(node) - s(:retry, [], smap_keyword_bare(srange_node(node), srange_node(node))) - end - - # Visit a ReturnNode node. - def visit_return(node) - s( - :return, - node.arguments ? visit_all(node.arguments.parts) : [], - smap_keyword_bare( - srange_length(node.start_char, 6), - srange_node(node) - ) - ) - end - - # Visit an SClass node. - def visit_sclass(node) - s( - :sclass, - [visit(node.target), visit(node.bodystmt)], - smap_definition( - srange_length(node.start_char, 5), - srange_find(node.start_char + 5, node.target.start_char, "<<"), - nil, - srange_length(node.end_char, -3) - ).with_expression(srange_node(node)) - ) - end - - # Visit a Statements node. - def visit_statements(node) - children = - node.body.reject do |child| - child.is_a?(Comment) || child.is_a?(EmbDoc) || - child.is_a?(EndContent) || child.is_a?(VoidStmt) - end - - case children.length - when 0 - nil - when 1 - visit(children.first) - else - s( - :begin, - visit_all(children), - smap_collection_bare( - srange(children.first.start_char, children.last.end_char) - ) - ) - end - end - - # Visit a StringConcat node. - def visit_string_concat(node) - s( - :dstr, - [visit(node.left), visit(node.right)], - smap_collection_bare(srange_node(node)) - ) - end - - # Visit a StringDVar node. - def visit_string_dvar(node) - visit(node.variable) - end - - # Visit a StringEmbExpr node. - def visit_string_embexpr(node) - s( - :begin, - visit(node.statements).then { |child| child ? [child] : [] }, - smap_collection( - srange_length(node.start_char, 2), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - end - - # Visit a StringLiteral node. - def visit_string_literal(node) - location = - if node.quote - smap_collection( - srange_length(node.start_char, node.quote.length), - srange_length(node.end_char, -1), - srange_node(node) - ) - else - smap_collection_bare(srange_node(node)) - end - - if node.parts.empty? - s(:str, [""], location) - elsif node.parts.length == 1 && node.parts.first.is_a?(TStringContent) - child = visit(node.parts.first) - s(child.type, child.children, location) - else - s(:dstr, visit_all(node.parts), location) - end - end - - # Visit a Super node. - def visit_super(node) - if node.arguments.is_a?(Args) - s( - :super, - visit_all(node.arguments.parts), - smap_keyword_bare( - srange_length(node.start_char, 5), - srange_node(node) - ) - ) - else - case node.arguments.arguments - when nil - s( - :super, - [], - smap_keyword( - srange_length(node.start_char, 5), - srange_find(node.start_char + 5, node.end_char, "("), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - when ArgsForward - s( - :super, - [visit(node.arguments.arguments)], - smap_keyword( - srange_length(node.start_char, 5), - srange_find(node.start_char + 5, node.end_char, "("), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - else - s( - :super, - visit_all(node.arguments.arguments.parts), - smap_keyword( - srange_length(node.start_char, 5), - srange_find(node.start_char + 5, node.end_char, "("), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - end - end - end - - # Visit a SymbolLiteral node. - def visit_symbol_literal(node) - begin_token = - if buffer.source[node.start_char] == ":" - srange_length(node.start_char, 1) - end - - s( - :sym, - [node.value.value.to_sym], - smap_collection(begin_token, nil, srange_node(node)) - ) - end - - # Visit a Symbols node. - def visit_symbols(node) - parts = - node.elements.map do |element| - part = element.parts.first - - if element.parts.length == 1 && part.is_a?(TStringContent) - SymbolLiteral.new(value: part, location: part.location) - else - DynaSymbol.new( - parts: element.parts, - quote: nil, - location: element.location - ) - end - end - - visit_array( - ArrayLiteral.new( - lbracket: node.beginning, - contents: Args.new(parts: parts, location: node.location), - location: node.location - ) - ) - end - - # Visit a TopConstField node. - def visit_top_const_field(node) - s( - :casgn, - [ - s(:cbase, [], smap(srange_length(node.start_char, 2))), - node.constant.value.to_sym - ], - smap_constant( - srange_length(node.start_char, 2), - srange_node(node.constant), - srange_node(node) - ) - ) - end - - # Visit a TopConstRef node. - def visit_top_const_ref(node) - s( - :const, - [ - s(:cbase, [], smap(srange_length(node.start_char, 2))), - node.constant.value.to_sym - ], - smap_constant( - srange_length(node.start_char, 2), - srange_node(node.constant), - srange_node(node) - ) - ) - end - - # Visit a TStringContent node. - def visit_tstring_content(node) - dumped = node.value.gsub(/([^[:ascii:]])/) { $1.dump[1...-1] } - - s( - :str, - ["\"#{dumped}\"".undump], - smap_collection_bare(srange_node(node)) - ) - end - - # Visit a Unary node. - def visit_unary(node) - # Special handling here for flipflops - if (paren = node.statement).is_a?(Paren) && - paren.contents.is_a?(Statements) && - paren.contents.body.length == 1 && - (range = paren.contents.body.first).is_a?(RangeNode) && - node.operator == "!" - s( - :send, - [ - s( - :begin, - [ - s( - range.operator.value == ".." ? :iflipflop : :eflipflop, - visit(range).children, - smap_operator( - srange_node(range.operator), - srange_node(range) - ) - ) - ], - smap_collection( - srange_length(paren.start_char, 1), - srange_length(paren.end_char, -1), - srange_node(paren) - ) - ), - :! - ], - smap_send_bare( - srange_length(node.start_char, 1), - srange_node(node) - ) - ) - elsif node.operator == "!" && node.statement.is_a?(RegexpLiteral) - s( - :send, - [ - s( - :match_current_line, - [visit(node.statement)], - smap(srange_node(node.statement)) - ), - :! - ], - smap_send_bare( - srange_length(node.start_char, 1), - srange_node(node) - ) - ) - else - visit(canonical_unary(node)) - end - end - - # Visit an Undef node. - def visit_undef(node) - s( - :undef, - visit_all(node.symbols), - smap_keyword_bare( - srange_length(node.start_char, 5), - srange_node(node) - ) - ) - end - - # Visit an UnlessNode node. - def visit_unless(node) - s( - :if, - [ - visit_predicate(node.predicate), - visit(node.consequent), - visit(node.statements) - ], - if node.modifier? - smap_keyword_bare( - srange_find_between(node.statements, node.predicate, "unless"), - srange_node(node) - ) - else - begin_start = node.predicate.end_char - begin_end = - if node.statements.empty? - node.statements.end_char - else - node.statements.body.first.start_char - end - - begin_token = - if buffer.source[begin_start...begin_end].include?("then") - srange_find(begin_start, begin_end, "then") - elsif buffer.source[begin_start...begin_end].include?(";") - srange_find(begin_start, begin_end, ";") - end - - else_token = - if node.consequent - srange_length(node.consequent.start_char, 4) - end - - smap_condition( - srange_length(node.start_char, 6), - begin_token, - else_token, - srange_length(node.end_char, -3), - srange_node(node) - ) - end - ) - end - - # Visit an UntilNode node. - def visit_until(node) - s( - loop_post?(node) ? :until_post : :until, - [visit(node.predicate), visit(node.statements)], - if node.modifier? - smap_keyword_bare( - srange_find_between(node.statements, node.predicate, "until"), - srange_node(node) - ) - else - smap_keyword( - srange_length(node.start_char, 5), - srange_search_between(node.predicate, node.statements, "do") || - srange_search_between(node.predicate, node.statements, ";"), - srange_length(node.end_char, -3), - srange_node(node) - ) - end - ) - end - - # Visit a VarField node. - def visit_var_field(node) - name = node.value.value.to_sym - match_var = - [stack[-3], stack[-2]].any? do |parent| - case parent - when AryPtn, FndPtn, HshPtn, In, RAssign - true - when Binary - parent.operator == :"=>" - else - false - end - end - - if match_var - s( - :match_var, - [name], - smap_variable(srange_node(node.value), srange_node(node.value)) - ) - elsif node.value.is_a?(Const) - s( - :casgn, - [nil, name], - smap_constant(nil, srange_node(node.value), srange_node(node)) - ) - else - location = smap_variable(srange_node(node), srange_node(node)) - - case node.value - when CVar - s(:cvasgn, [name], location) - when GVar - s(:gvasgn, [name], location) - when Ident - s(:lvasgn, [name], location) - when IVar - s(:ivasgn, [name], location) - when VarRef - s(:lvasgn, [name], location) - else - s(:match_rest, [], nil) - end - end - end - - # Visit a VarRef node. - def visit_var_ref(node) - visit(node.value) - end - - # Visit a VCall node. - def visit_vcall(node) - visit_command_call( - CommandCall.new( - receiver: nil, - operator: nil, - message: node.value, - arguments: nil, - block: nil, - location: node.location - ) - ) - end - - # Visit a When node. - def visit_when(node) - keyword = srange_length(node.start_char, 4) - begin_token = - if buffer.source[node.statements.start_char] == ";" - srange_length(node.statements.start_char, 1) - end - - end_char = - if node.statements.body.empty? - node.statements.end_char - else - node.statements.body.last.end_char - end - - s( - :when, - visit_all(node.arguments.parts) + [visit(node.statements)], - smap_keyword( - keyword, - begin_token, - nil, - srange(keyword.begin_pos, end_char) - ) - ) - end - - # Visit a WhileNode node. - def visit_while(node) - s( - loop_post?(node) ? :while_post : :while, - [visit(node.predicate), visit(node.statements)], - if node.modifier? - smap_keyword_bare( - srange_find_between(node.statements, node.predicate, "while"), - srange_node(node) - ) - else - smap_keyword( - srange_length(node.start_char, 5), - srange_search_between(node.predicate, node.statements, "do") || - srange_search_between(node.predicate, node.statements, ";"), - srange_length(node.end_char, -3), - srange_node(node) - ) - end - ) - end - - # Visit a Word node. - def visit_word(node) - visit_string_literal( - StringLiteral.new( - parts: node.parts, - quote: nil, - location: node.location - ) - ) - end - - # Visit a Words node. - def visit_words(node) - visit_array( - ArrayLiteral.new( - lbracket: node.beginning, - contents: Args.new(parts: node.elements, location: node.location), - location: node.location - ) - ) - end - - # Visit an XStringLiteral node. - def visit_xstring_literal(node) - s( - :xstr, - visit_all(node.parts), - smap_collection( - srange_length( - node.start_char, - buffer.source[node.start_char] == "%" ? 3 : 1 - ), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - end - - def visit_yield(node) - case node.arguments - when nil - s( - :yield, - [], - smap_keyword_bare( - srange_length(node.start_char, 5), - srange_node(node) - ) - ) - when Args - s( - :yield, - visit_all(node.arguments.parts), - smap_keyword_bare( - srange_length(node.start_char, 5), - srange_node(node) - ) - ) - else - s( - :yield, - visit_all(node.arguments.contents.parts), - smap_keyword( - srange_length(node.start_char, 5), - srange_length(node.arguments.start_char, 1), - srange_length(node.end_char, -1), - srange_node(node) - ) - ) - end - end - - # Visit a ZSuper node. - def visit_zsuper(node) - s( - :zsuper, - [], - smap_keyword_bare( - srange_length(node.start_char, 5), - srange_node(node) - ) - ) - end - end - - private - - def block_children(node) - arguments = - if node.block_var - visit(node.block_var) - else - s(:args, [], smap_collection_bare(nil)) - end - - type = :block - if !node.block_var && (maximum = num_block_type(node.bodystmt)) - type = :numblock - arguments = maximum - end - - [type, arguments] - end - - # Convert a Unary node into a canonical CommandCall node. - def canonical_unary(node) - # For integers and floats with a leading + or -, parser represents them - # as just their values with the signs attached. - if %w[+ -].include?(node.operator) && - (node.statement.is_a?(Int) || node.statement.is_a?(FloatLiteral)) - return( - node.statement.class.new( - value: "#{node.operator}#{node.statement.value}", - location: node.location - ) - ) - end - - value = { "+" => "+@", "-" => "-@" }.fetch(node.operator, node.operator) - length = node.operator.length - - CommandCall.new( - receiver: node.statement, - operator: nil, - message: - Op.new( - value: value, - location: - Location.new( - start_line: node.location.start_line, - start_char: node.start_char, - start_column: node.location.start_column, - end_line: node.location.start_line, - end_char: node.start_char + length, - end_column: node.location.start_column + length - ) - ), - arguments: nil, - block: nil, - location: node.location - ) - end - - # Convert a Binary node into a canonical CommandCall node. - def canonical_binary(node) - operator = node.operator.to_s - - start_char = node.left.end_char - end_char = node.right.start_char - - index = buffer.source[start_char...end_char].index(operator) - start_line = - node.location.start_line + - buffer.source[start_char...index].count("\n") - start_column = - index - (buffer.source[start_char...index].rindex("\n") || 0) - - op_location = - Location.new( - start_line: start_line, - start_column: start_column, - start_char: start_char + index, - end_line: start_line, - end_column: start_column + operator.length, - end_char: start_char + index + operator.length - ) - - CommandCall.new( - receiver: node.left, - operator: nil, - message: Op.new(value: operator, location: op_location), - arguments: - Args.new(parts: [node.right], location: node.right.location), - block: nil, - location: node.location - ) - end - - # When you have a begin..end while or begin..end until, it's a special - # kind of syntax that executes the block in a loop. In this case the - # parser gem has a special node type for it. - def loop_post?(node) - node.modifier? && node.statements.is_a?(Statements) && - node.statements.body.length == 1 && - node.statements.body.first.is_a?(Begin) - end - - # We need to find if we should transform this block into a numblock - # since there could be new numbered variables like _1. - def num_block_type(statements) - variables = [] - queue = [statements] - - while (child_node = queue.shift) - if child_node.is_a?(VarRef) && child_node.value.is_a?(Ident) && - child_node.value.value =~ /^_(\d+)$/ - variables << $1.to_i - end - - queue += child_node.child_nodes.compact - end - - variables.max - end - - # This method comes almost directly from the parser gem and creates a new - # parser gem node from the given s-expression. type is expected to be a - # symbol, children is expected to be an array, and location is expected to - # be a source map. - def s(type, children, location) - ::Parser::AST::Node.new(type, children, location: location) - end - - # Constructs a plain source map just for an expression. - def smap(expression) - ::Parser::Source::Map.new(expression) - end - - # Constructs a new source map for a collection. - def smap_collection(begin_token, end_token, expression) - ::Parser::Source::Map::Collection.new( - begin_token, - end_token, - expression - ) - end - - # Constructs a new source map for a collection without a begin or end. - def smap_collection_bare(expression) - smap_collection(nil, nil, expression) - end - - # Constructs a new source map for a conditional expression. - def smap_condition( - keyword, - begin_token, - else_token, - end_token, - expression - ) - ::Parser::Source::Map::Condition.new( - keyword, - begin_token, - else_token, - end_token, - expression - ) - end - - # Constructs a new source map for a conditional expression with no begin - # or end. - def smap_condition_bare(expression) - smap_condition(nil, nil, nil, nil, expression) - end - - # Constructs a new source map for a constant reference. - def smap_constant(double_colon, name, expression) - ::Parser::Source::Map::Constant.new(double_colon, name, expression) - end - - # Constructs a new source map for a class definition. - def smap_definition(keyword, operator, name, end_token) - ::Parser::Source::Map::Definition.new( - keyword, - operator, - name, - end_token - ) - end - - # Constructs a new source map for a for loop. - def smap_for(keyword, in_token, begin_token, end_token, expression) - ::Parser::Source::Map::For.new( - keyword, - in_token, - begin_token, - end_token, - expression - ) - end - - # Constructs a new source map for a heredoc. - def smap_heredoc(expression, heredoc_body, heredoc_end) - ::Parser::Source::Map::Heredoc.new( - expression, - heredoc_body, - heredoc_end - ) - end - - # Construct a source map for an index operation. - def smap_index(begin_token, end_token, expression) - ::Parser::Source::Map::Index.new(begin_token, end_token, expression) - end - - # Constructs a new source map for the use of a keyword. - def smap_keyword(keyword, begin_token, end_token, expression) - ::Parser::Source::Map::Keyword.new( - keyword, - begin_token, - end_token, - expression - ) - end - - # Constructs a new source map for the use of a keyword without a begin or - # end token. - def smap_keyword_bare(keyword, expression) - smap_keyword(keyword, nil, nil, expression) - end - - # Constructs a new source map for a method definition. - def smap_method_definition( - keyword, - operator, - name, - end_token, - assignment, - expression - ) - ::Parser::Source::Map::MethodDefinition.new( - keyword, - operator, - name, - end_token, - assignment, - expression - ) - end - - # Constructs a new source map for an operator. - def smap_operator(operator, expression) - ::Parser::Source::Map::Operator.new(operator, expression) - end - - # Constructs a source map for the body of a rescue clause. - def smap_rescue_body(keyword, assoc, begin_token, expression) - ::Parser::Source::Map::RescueBody.new( - keyword, - assoc, - begin_token, - expression - ) - end - - # Constructs a new source map for a method call. - def smap_send(dot, selector, begin_token, end_token, expression) - ::Parser::Source::Map::Send.new( - dot, - selector, - begin_token, - end_token, - expression - ) - end - - # Constructs a new source map for a method call without a begin or end. - def smap_send_bare(selector, expression) - smap_send(nil, selector, nil, nil, expression) - end - - # Constructs a new source map for a ternary expression. - def smap_ternary(question, colon, expression) - ::Parser::Source::Map::Ternary.new(question, colon, expression) - end - - # Constructs a new source map for a variable. - def smap_variable(name, expression) - ::Parser::Source::Map::Variable.new(name, expression) - end - - # Constructs a new source range from the given start and end offsets. - def srange(start_char, end_char) - ::Parser::Source::Range.new(buffer, start_char, end_char) - end - - # Constructs a new source range by finding the given needle in the given - # range of the source. If the needle is not found, returns nil. - def srange_search(start_char, end_char, needle) - index = buffer.source[start_char...end_char].index(needle) - return unless index - - offset = start_char + index - srange(offset, offset + needle.length) - end - - # Constructs a new source range by searching for the given needle between - # the end location of the start node and the start location of the end - # node. If the needle is not found, returns nil. - def srange_search_between(start_node, end_node, needle) - srange_search(start_node.end_char, end_node.start_char, needle) - end - - # Constructs a new source range by finding the given needle in the given - # range of the source. If it needle is not found, raises an error. - def srange_find(start_char, end_char, needle) - srange = srange_search(start_char, end_char, needle) - - unless srange - slice = buffer.source[start_char...end_char].inspect - raise "Could not find #{needle.inspect} in #{slice}" - end - - srange - end - - # Constructs a new source range by finding the given needle between the - # end location of the start node and the start location of the end node. - # If the needle is not found, returns raises an error. - def srange_find_between(start_node, end_node, needle) - srange_find(start_node.end_char, end_node.start_char, needle) - end - - # Constructs a new source range from the given start offset and length. - def srange_length(start_char, length) - if length > 0 - srange(start_char, start_char + length) - else - srange(start_char + length, start_char) - end - end - - # Constructs a new source range using the given node's location. - def srange_node(node) - location = node.location - srange(location.start_char, location.end_char) - end - - def visit_predicate(node) - case node - when RangeNode - s( - node.operator.value == ".." ? :iflipflop : :eflipflop, - visit(node).children, - smap_operator(srange_node(node.operator), srange_node(node)) - ) - when RegexpLiteral - s(:match_current_line, [visit(node)], smap(srange_node(node))) - when Unary - if node.operator.value == "!" && node.statement.is_a?(RegexpLiteral) - s( - :send, - [s(:match_current_line, [visit(node.statement)]), :!], - smap_send_bare(srange_node(node.operator), srange_node(node)) - ) - else - visit(node) - end - else - visit(node) - end - end - end - end -end diff --git a/lib/syntax_tree/translation/rubocop_ast.rb b/lib/syntax_tree/translation/rubocop_ast.rb deleted file mode 100644 index 53c6737b..00000000 --- a/lib/syntax_tree/translation/rubocop_ast.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -module SyntaxTree - module Translation - # This visitor is responsible for converting the syntax tree produced by - # Syntax Tree into the syntax tree produced by the rubocop/rubocop-ast gem. - class RuboCopAST < Parser - private - - # This method is effectively the same thing as the parser gem except that - # it uses the rubocop-ast specializations of the nodes. - def s(type, children, location) - ::RuboCop::AST::Builder::NODE_MAP.fetch(type, ::RuboCop::AST::Node).new( - type, - children, - location: location - ) - end - end - end -end diff --git a/tasks/whitequark.rake b/tasks/whitequark.rake deleted file mode 100644 index 6e1663aa..00000000 --- a/tasks/whitequark.rake +++ /dev/null @@ -1,92 +0,0 @@ -# frozen_string_literal: true - -# This file's purpose is to extract the examples from the whitequark/parser -# gem and generate a test file that we can use to ensure that our parser -# generates equivalent syntax trees when translating. To do this, it runs the -# parser's test suite but overrides the `assert_parses` method to collect the -# examples into a hash. Then, it writes out the hash to a file that we can use -# to generate our own tests. -# -# To run the test suite, it's important to note that we have to mirror both any -# APIs provided to the test suite (for example the ParseHelper module below). -# This is obviously relatively brittle, but it's effective for now. - -require "ast" - -module ParseHelper - # This object is going to collect all of the examples from the parser gem into - # a hash that we can use to generate our own tests. - COLLECTED = Hash.new { |hash, key| hash[key] = [] } - - include AST::Sexp - ALL_VERSIONS = %w[3.1 3.2] - - private - - def assert_context(*) - end - - def assert_diagnoses(*) - end - - def assert_diagnoses_many(*) - end - - def refute_diagnoses(*) - end - - def with_versions(*) - end - - def assert_parses(_ast, code, _source_maps = "", versions = ALL_VERSIONS) - # We're going to skip any examples that are for older Ruby versions - # that we do not support. - return if (versions & %w[3.1 3.2]).empty? - - entry = - caller.find do |call| - call.include?("test_parser.rb") && call.match?(%r{(? 1) -!!! test_args_args_assocs:4143 -fun(foo, :foo => 1, &baz) -!!! test_args_args_assocs_comma:4152 -foo[bar, :baz => 1,] -!!! test_args_args_comma:4001 -foo[bar,] -!!! test_args_args_star:3968 -fun(foo, *bar) -!!! test_args_args_star:3973 -fun(foo, *bar, &baz) -!!! test_args_assocs:4061 -fun(:foo => 1) -!!! test_args_assocs:4066 -fun(:foo => 1, &baz) -!!! test_args_assocs:4072 -self[:bar => 1] -!!! test_args_assocs:4081 -self.[]= foo, :a => 1 -!!! test_args_assocs:4091 -yield(:foo => 42) -!!! test_args_assocs:4099 -super(:foo => 42) -!!! test_args_assocs_comma:4128 -foo[:baz => 1,] -!!! test_args_assocs_legacy:4011 -fun(:foo => 1) -!!! test_args_assocs_legacy:4016 -fun(:foo => 1, &baz) -!!! test_args_assocs_legacy:4022 -self[:bar => 1] -!!! test_args_assocs_legacy:4031 -self.[]= foo, :a => 1 -!!! test_args_assocs_legacy:4041 -yield(:foo => 42) -!!! test_args_assocs_legacy:4049 -super(:foo => 42) -!!! test_args_block_pass:3994 -fun(&bar) -!!! test_args_cmd:3961 -fun(f bar) -!!! test_args_star:3981 -fun(*bar) -!!! test_args_star:3986 -fun(*bar, &baz) -!!! test_array_assocs:643 -[ 1 => 2 ] -!!! test_array_assocs:651 -[ 1, 2 => 3 ] -!!! test_array_plain:603 -[1, 2] -!!! test_array_splat:612 -[1, *foo, 2] -!!! test_array_splat:625 -[1, *foo] -!!! test_array_splat:636 -[*foo] -!!! test_array_symbols:709 -%i[foo bar] -!!! test_array_symbols_empty:746 -%i[] -!!! test_array_symbols_empty:754 -%I() -!!! test_array_symbols_interp:720 -%I[foo #{bar}] -!!! test_array_symbols_interp:735 -%I[foo#{bar}] -!!! test_array_words:661 -%w[foo bar] -!!! test_array_words_empty:696 -%w[] -!!! test_array_words_empty:703 -%W() -!!! test_array_words_interp:671 -%W[foo #{bar}] -!!! test_array_words_interp:685 -%W[foo #{bar}foo#@baz] -!!! test_asgn_cmd:1140 -foo = m foo -!!! test_asgn_cmd:1144 -foo = bar = m foo -!!! test_asgn_mrhs:1463 -foo = bar, 1 -!!! test_asgn_mrhs:1470 -foo = *bar -!!! test_asgn_mrhs:1475 -foo = baz, *bar -!!! test_back_ref:1009 -$+ -!!! test_bang:3448 -!foo -!!! test_bang_cmd:3462 -!m foo -!!! test_begin_cmdarg:5658 -p begin 1.times do 1 end end -!!! test_beginless_erange_after_newline:949 -foo -...100 -!!! test_beginless_irange_after_newline:937 -foo -..100 -!!! test_beginless_range:917 -..100 -!!! test_beginless_range:926 -...100 -!!! test_block_arg_combinations:2531 -f{ } -!!! test_block_arg_combinations:2537 -f{ | | } -!!! test_block_arg_combinations:2541 -f{ |;a| } -!!! test_block_arg_combinations:2546 -f{ |; -a -| } -!!! test_block_arg_combinations:2552 -f{ || } -!!! test_block_arg_combinations:2561 -f{ |a| } -!!! test_block_arg_combinations:2571 -f{ |a, c| } -!!! test_block_arg_combinations:2580 -f{ |a,| } -!!! test_block_arg_combinations:2585 -f{ |a, &b| } -!!! test_block_arg_combinations:2599 -f{ |a, *s, &b| } -!!! test_block_arg_combinations:2610 -f{ |a, *, &b| } -!!! test_block_arg_combinations:2621 -f{ |a, *s| } -!!! test_block_arg_combinations:2631 -f{ |a, *| } -!!! test_block_arg_combinations:2640 -f{ |*s, &b| } -!!! test_block_arg_combinations:2651 -f{ |*, &b| } -!!! test_block_arg_combinations:2662 -f{ |*s| } -!!! test_block_arg_combinations:2672 -f{ |*| } -!!! test_block_arg_combinations:2678 -f{ |&b| } -!!! test_block_arg_combinations:2689 -f{ |a, o=1, o1=2, *r, &b| } -!!! test_block_arg_combinations:2700 -f{ |a, o=1, *r, p, &b| } -!!! test_block_arg_combinations:2711 -f{ |a, o=1, &b| } -!!! test_block_arg_combinations:2720 -f{ |a, o=1, p, &b| } -!!! test_block_arg_combinations:2730 -f{ |a, *r, p, &b| } -!!! test_block_arg_combinations:2740 -f{ |o=1, *r, &b| } -!!! test_block_arg_combinations:2749 -f{ |o=1, *r, p, &b| } -!!! test_block_arg_combinations:2759 -f{ |o=1, &b| } -!!! test_block_arg_combinations:2767 -f{ |o=1, p, &b| } -!!! test_block_arg_combinations:2776 -f{ |*r, p, &b| } -!!! test_block_kwarg:2867 -f{ |foo:| } -!!! test_block_kwarg_combinations:2840 -f{ |foo: 1, bar: 2, **baz, &b| } -!!! test_block_kwarg_combinations:2850 -f{ |foo: 1, &b| } -!!! test_block_kwarg_combinations:2858 -f{ |**baz, &b| } -!!! test_blockarg:2201 -def f(&block); end -!!! test_break:5169 -break(foo) -!!! test_break:5183 -break foo -!!! test_break:5189 -break() -!!! test_break:5196 -break -!!! test_break_block:5204 -break fun foo do end -!!! test_bug_435:7252 -"#{-> foo {}}" -!!! test_bug_447:7231 -m [] do end -!!! test_bug_447:7240 -m [], 1 do end -!!! test_bug_452:7265 -td (1_500).toString(); td.num do; end -!!! test_bug_466:7281 -foo "#{(1+1).to_i}" do; end -!!! test_bug_473:7298 -m "#{[]}" -!!! test_bug_480:7309 -m "#{}#{()}" -!!! test_bug_481:7321 -m def x(); end; 1.tap do end -!!! test_bug_ascii_8bit_in_literal:6031 -# coding:utf-8 - "\xD0\xBF\xD1\x80\xD0\xBE\xD0\xB2\xD0\xB5\xD1\x80\xD0\xBA\xD0\xB0" -!!! test_bug_cmd_string_lookahead:5903 -desc "foo" do end -!!! test_bug_cmdarg:5681 -assert dogs -!!! test_bug_cmdarg:5686 -assert do: true -!!! test_bug_cmdarg:5694 -f x: -> do meth do end end -!!! test_bug_def_no_paren_eql_begin:5950 -def foo -=begin -=end -end -!!! test_bug_do_block_in_call_args:5913 -bar def foo; self.each do end end -!!! test_bug_do_block_in_cmdarg:5928 -tap (proc do end) -!!! test_bug_do_block_in_hash_brace:6720 -p :foo, {a: proc do end, b: proc do end} -!!! test_bug_do_block_in_hash_brace:6738 -p :foo, {:a => proc do end, b: proc do end} -!!! test_bug_do_block_in_hash_brace:6756 -p :foo, {"a": proc do end, b: proc do end} -!!! test_bug_do_block_in_hash_brace:6774 -p :foo, {proc do end => proc do end, b: proc do end} -!!! test_bug_do_block_in_hash_brace:6794 -p :foo, {** proc do end, b: proc do end} -!!! test_bug_heredoc_do:5986 -f <<-TABLE do -TABLE -end -!!! test_bug_interp_single:5940 -"#{1}" -!!! test_bug_interp_single:5944 -%W"#{1}" -!!! test_bug_lambda_leakage:6701 -->(scope) {}; scope -!!! test_bug_regex_verification:6714 -/#)/x -!!! test_bug_rescue_empty_else:5964 -begin; rescue LoadError; else; end -!!! test_bug_while_not_parens_do:5956 -while not (true) do end -!!! test_case_cond:4976 -case; when foo; 'foo'; end -!!! test_case_cond_else:4989 -case; when foo; 'foo'; else 'bar'; end -!!! test_case_expr:4948 -case foo; when 'bar'; bar; end -!!! test_case_expr_else:4962 -case foo; when 'bar'; bar; else baz; end -!!! test_casgn_scoped:1206 -Bar::Foo = 10 -!!! test_casgn_toplevel:1195 -::Foo = 10 -!!! test_casgn_unscoped:1217 -Foo = 10 -!!! test_character:250 -?a -!!! test_class:1841 -class Foo; end -!!! test_class:1851 -class Foo end -!!! test_class_definition_in_while_cond:7055 -while class Foo; tap do end; end; break; end -!!! test_class_definition_in_while_cond:7067 -while class Foo a = tap do end; end; break; end -!!! test_class_definition_in_while_cond:7080 -while class << self; tap do end; end; break; end -!!! test_class_definition_in_while_cond:7092 -while class << self; a = tap do end; end; break; end -!!! test_class_super:1862 -class Foo < Bar; end -!!! test_class_super_label:1874 -class Foo < a:b; end -!!! test_comments_before_leading_dot__27:7941 -a # -# -.foo -!!! test_comments_before_leading_dot__27:7948 -a # - # -.foo -!!! test_comments_before_leading_dot__27:7955 -a # -# -&.foo -!!! test_comments_before_leading_dot__27:7962 -a # - # -&.foo -!!! test_complex:158 -42i -!!! test_complex:164 -42ri -!!! test_complex:170 -42.1i -!!! test_complex:176 -42.1ri -!!! test_cond_begin:4746 -if (bar); foo; end -!!! test_cond_begin_masgn:4755 -if (bar; a, b = foo); end -!!! test_cond_eflipflop:4854 -if foo...bar; end -!!! test_cond_eflipflop:4884 -!(foo...bar) -!!! test_cond_eflipflop_with_beginless_range:4903 -if ...bar; end -!!! test_cond_eflipflop_with_endless_range:4893 -if foo...; end -!!! test_cond_iflipflop:4795 -if foo..bar; end -!!! test_cond_iflipflop:4825 -!(foo..bar) -!!! test_cond_iflipflop_with_beginless_range:4844 -if ..bar; end -!!! test_cond_iflipflop_with_endless_range:4834 -if foo..; end -!!! test_cond_match_current_line:4913 -if /wat/; end -!!! test_cond_match_current_line:4933 -!/wat/ -!!! test_const_op_asgn:1550 -A += 1 -!!! test_const_op_asgn:1556 -::A += 1 -!!! test_const_op_asgn:1564 -B::A += 1 -!!! test_const_op_asgn:1572 -def x; self::A ||= 1; end -!!! test_const_op_asgn:1581 -def x; ::A ||= 1; end -!!! test_const_scoped:1034 -Bar::Foo -!!! test_const_toplevel:1025 -::Foo -!!! test_const_unscoped:1043 -Foo -!!! test_control_meta_escape_chars_in_regexp__since_31:11030 -/\c\xFF/ -!!! test_control_meta_escape_chars_in_regexp__since_31:11036 -/\c\M-\xFF/ -!!! test_control_meta_escape_chars_in_regexp__since_31:11042 -/\C-\xFF/ -!!! test_control_meta_escape_chars_in_regexp__since_31:11048 -/\C-\M-\xFF/ -!!! test_control_meta_escape_chars_in_regexp__since_31:11054 -/\M-\xFF/ -!!! test_control_meta_escape_chars_in_regexp__since_31:11060 -/\M-\C-\xFF/ -!!! test_control_meta_escape_chars_in_regexp__since_31:11066 -/\M-\c\xFF/ -!!! test_cpath:1821 -module ::Foo; end -!!! test_cpath:1827 -module Bar::Foo; end -!!! test_cvar:987 -@@foo -!!! test_cvasgn:1120 -@@var = 10 -!!! test_dedenting_heredoc:299 -p <<~E -E -!!! test_dedenting_heredoc:306 -p <<~E - E -!!! test_dedenting_heredoc:313 -p <<~E - x -E -!!! test_dedenting_heredoc:320 -p <<~E - ð -E -!!! test_dedenting_heredoc:327 -p <<~E - x - y -E -!!! test_dedenting_heredoc:336 -p <<~E - x - y -E -!!! test_dedenting_heredoc:345 -p <<~E - x - y -E -!!! test_dedenting_heredoc:354 -p <<~E - x - y -E -!!! test_dedenting_heredoc:363 -p <<~E - x - y -E -!!! test_dedenting_heredoc:372 -p <<~E - x - -y -E -!!! test_dedenting_heredoc:382 -p <<~E - x - - y -E -!!! test_dedenting_heredoc:392 -p <<~E - x - \ y -E -!!! test_dedenting_heredoc:401 -p <<~E - x - \ y -E -!!! test_dedenting_heredoc:410 -p <<~"E" - x - #{foo} -E -!!! test_dedenting_heredoc:421 -p <<~`E` - x - #{foo} -E -!!! test_dedenting_heredoc:432 -p <<~"E" - x - #{" y"} -E -!!! test_dedenting_interpolating_heredoc_fake_line_continuation:461 -<<~'FOO' - baz\\ - qux -FOO -!!! test_dedenting_non_interpolating_heredoc_line_continuation:453 -<<~'FOO' - baz\ - qux -FOO -!!! test_def:1913 -def foo; end -!!! test_def:1921 -def String; end -!!! test_def:1925 -def String=; end -!!! test_def:1929 -def until; end -!!! test_def:1933 -def BEGIN; end -!!! test_def:1937 -def END; end -!!! test_defined:1072 -defined? foo -!!! test_defined:1078 -defined?(foo) -!!! test_defined:1086 -defined? @foo -!!! test_defs:1943 -def self.foo; end -!!! test_defs:1951 -def self::foo; end -!!! test_defs:1959 -def (foo).foo; end -!!! test_defs:1963 -def String.foo; end -!!! test_defs:1968 -def String::foo; end -!!! test_emit_arg_inside_procarg0_legacy:2807 -f{ |a| } -!!! test_empty_stmt:62 -!!! test_endless_comparison_method:10736:0 -def ===(other) = do_something -!!! test_endless_comparison_method:10736:1 -def ==(other) = do_something -!!! test_endless_comparison_method:10736:2 -def !=(other) = do_something -!!! test_endless_comparison_method:10736:3 -def <=(other) = do_something -!!! test_endless_comparison_method:10736:4 -def >=(other) = do_something -!!! test_endless_comparison_method:10736:5 -def !=(other) = do_something -!!! test_endless_method:10085 -def foo() = 42 -!!! test_endless_method:10097 -def inc(x) = x + 1 -!!! test_endless_method:10110 -def obj.foo() = 42 -!!! test_endless_method:10122 -def obj.inc(x) = x + 1 -!!! test_endless_method_command_syntax:10179 -def foo = puts "Hello" -!!! test_endless_method_command_syntax:10191 -def foo() = puts "Hello" -!!! test_endless_method_command_syntax:10203 -def foo(x) = puts x -!!! test_endless_method_command_syntax:10216 -def obj.foo = puts "Hello" -!!! test_endless_method_command_syntax:10230 -def obj.foo() = puts "Hello" -!!! test_endless_method_command_syntax:10244 -def rescued(x) = raise "to be caught" rescue "instance #{x}" -!!! test_endless_method_command_syntax:10263 -def self.rescued(x) = raise "to be caught" rescue "class #{x}" -!!! test_endless_method_command_syntax:10284 -def obj.foo(x) = puts x -!!! test_endless_method_forwarded_args_legacy:10139 -def foo(...) = bar(...) -!!! test_endless_method_with_rescue_mod:10154 -def m() = 1 rescue 2 -!!! test_endless_method_with_rescue_mod:10165 -def self.m() = 1 rescue 2 -!!! test_endless_method_without_args:10748 -def foo = 42 -!!! test_endless_method_without_args:10756 -def foo = 42 rescue nil -!!! test_endless_method_without_args:10767 -def self.foo = 42 -!!! test_endless_method_without_args:10776 -def self.foo = 42 rescue nil -!!! test_ensure:5393 -begin; meth; ensure; bar; end -!!! test_ensure_empty:5406 -begin ensure end -!!! test_false:98 -false -!!! test_find_pattern:10447 -case foo; in [*x, 1 => a, *y] then true; end -!!! test_find_pattern:10467 -case foo; in String(*, 1, *) then true; end -!!! test_find_pattern:10481 -case foo; in Array[*, 1, *] then true; end -!!! test_find_pattern:10495 -case foo; in *, 42, * then true; end -!!! test_float:131 -1.33 -!!! test_float:136 --1.33 -!!! test_for:5134 -for a in foo do p a; end -!!! test_for:5146 -for a in foo; p a; end -!!! test_for_mlhs:5155 -for a, b in foo; p a, b; end -!!! test_forward_arg:8090 -def foo(...); bar(...); end -!!! test_forward_arg_with_open_args:11089 -def foo ... -end -!!! test_forward_arg_with_open_args:11096 -def foo a, b = 1, ... -end -!!! test_forward_arg_with_open_args:11114 -def foo(a, ...) bar(...) end -!!! test_forward_arg_with_open_args:11125 -def foo a, ... - bar(...) -end -!!! test_forward_arg_with_open_args:11136 -def foo b = 1, ... - bar(...) -end -!!! test_forward_arg_with_open_args:11148 -def foo ...; bar(...); end -!!! test_forward_arg_with_open_args:11158 -def foo a, ...; bar(...); end -!!! test_forward_arg_with_open_args:11169 -def foo b = 1, ...; bar(...); end -!!! test_forward_arg_with_open_args:11181 -(def foo ... - bar(...) -end) -!!! test_forward_arg_with_open_args:11192 -(def foo ...; bar(...); end) -!!! test_forward_args_legacy:8054 -def foo(...); bar(...); end -!!! test_forward_args_legacy:8066 -def foo(...); super(...); end -!!! test_forward_args_legacy:8078 -def foo(...); end -!!! test_forwarded_argument_with_kwrestarg:11332 -def foo(argument, **); bar(argument, **); end -!!! test_forwarded_argument_with_restarg:11267 -def foo(argument, *); bar(argument, *); end -!!! test_forwarded_kwrestarg:11287 -def foo(**); bar(**); end -!!! test_forwarded_kwrestarg_with_additional_kwarg:11306 -def foo(**); bar(**, from_foo: true); end -!!! test_forwarded_restarg:11249 -def foo(*); bar(*); end -!!! test_gvar:994 -$foo -!!! test_gvasgn:1130 -$var = 10 -!!! test_hash_empty:764 -{ } -!!! test_hash_hashrocket:773 -{ 1 => 2 } -!!! test_hash_hashrocket:782 -{ 1 => 2, :foo => "bar" } -!!! test_hash_kwsplat:835 -{ foo: 2, **bar } -!!! test_hash_label:790 -{ foo: 2 } -!!! test_hash_label_end:803 -{ 'foo': 2 } -!!! test_hash_label_end:816 -{ 'foo': 2, 'bar': {}} -!!! test_hash_label_end:824 -f(a ? "a":1) -!!! test_hash_pair_value_omission:10339 -{a:, b:} -!!! test_hash_pair_value_omission:10353 -{puts:} -!!! test_hash_pair_value_omission:10364 -foo = 1; {foo:} -!!! test_hash_pair_value_omission:10376 -_foo = 1; {_foo:} -!!! test_hash_pair_value_omission:10388 -{BAR:} -!!! test_heredoc:265 -<(**nil) {} -!!! test_kwoptarg:2138 -def f(foo: 1); end -!!! test_kwoptarg_with_kwrestarg_and_forwarded_args:11482 -def f(a: nil, **); b(**) end -!!! test_kwrestarg_named:2149 -def f(**foo); end -!!! test_kwrestarg_unnamed:2160 -def f(**); end -!!! test_lbrace_arg_after_command_args:7420 -let (:a) { m do; end } -!!! test_lparenarg_after_lvar__since_25:6830 -meth (-1.3).abs -!!! test_lparenarg_after_lvar__since_25:6839 -foo (-1.3).abs -!!! test_lvar:973 -foo -!!! test_lvar_injecting_match:3819 -/(?bar)/ =~ 'bar'; match -!!! test_lvasgn:1098 -var = 10; var -!!! test_marg_combinations:2454 -def f (((a))); end -!!! test_marg_combinations:2460 -def f ((a, a1)); end -!!! test_marg_combinations:2465 -def f ((a, *r)); end -!!! test_marg_combinations:2470 -def f ((a, *r, p)); end -!!! test_marg_combinations:2475 -def f ((a, *)); end -!!! test_marg_combinations:2480 -def f ((a, *, p)); end -!!! test_marg_combinations:2485 -def f ((*r)); end -!!! test_marg_combinations:2490 -def f ((*r, p)); end -!!! test_marg_combinations:2495 -def f ((*)); end -!!! test_marg_combinations:2500 -def f ((*, p)); end -!!! test_masgn:1261 -foo, bar = 1, 2 -!!! test_masgn:1272 -(foo, bar) = 1, 2 -!!! test_masgn:1282 -foo, bar, baz = 1, 2 -!!! test_masgn_attr:1404 -self.a, self[1, 2] = foo -!!! test_masgn_attr:1417 -self::a, foo = foo -!!! test_masgn_attr:1425 -self.A, foo = foo -!!! test_masgn_cmd:1453 -foo, bar = m foo -!!! test_masgn_const:1435 -self::A, foo = foo -!!! test_masgn_const:1443 -::A, foo = foo -!!! test_masgn_nested:1379 -a, (b, c) = foo -!!! test_masgn_nested:1393 -((b, )) = foo -!!! test_masgn_splat:1293 -@foo, @@bar = *foo -!!! test_masgn_splat:1302 -a, b = *foo, bar -!!! test_masgn_splat:1310 -a, *b = bar -!!! test_masgn_splat:1316 -a, *b, c = bar -!!! test_masgn_splat:1327 -a, * = bar -!!! test_masgn_splat:1333 -a, *, c = bar -!!! test_masgn_splat:1344 -*b = bar -!!! test_masgn_splat:1350 -*b, c = bar -!!! test_masgn_splat:1360 -* = bar -!!! test_masgn_splat:1366 -*, c, d = bar -!!! test_method_definition_in_while_cond:7001 -while def foo; tap do end; end; break; end -!!! test_method_definition_in_while_cond:7013 -while def self.foo; tap do end; end; break; end -!!! test_method_definition_in_while_cond:7026 -while def foo a = tap do end; end; break; end -!!! test_method_definition_in_while_cond:7039 -while def self.foo a = tap do end; end; break; end -!!! test_module:1803 -module Foo; end -!!! test_multiple_args_with_trailing_comma:2786 -f{ |a, b,| } -!!! test_multiple_pattern_matches:11456 -{a: 0} => a: -{a: 0} => a: -!!! test_multiple_pattern_matches:11472 -{a: 0} in a: -{a: 0} in a: -!!! test_newline_in_hash_argument:11405 -obj.set foo: -1 -!!! test_newline_in_hash_argument:11416 -obj.set "foo": -1 -!!! test_newline_in_hash_argument:11427 -case foo -in a: -0 -true -in "b": -0 -true -end -!!! test_next:5263 -next(foo) -!!! test_next:5277 -next foo -!!! test_next:5283 -next() -!!! test_next:5290 -next -!!! test_next_block:5298 -next fun foo do end -!!! test_nil:68 -nil -!!! test_nil_expression:75 -() -!!! test_nil_expression:82 -begin end -!!! test_non_lvar_injecting_match:3853 -/#{1}(?bar)/ =~ 'bar' -!!! test_not:3476 -not foo -!!! test_not:3482 -not(foo) -!!! test_not:3488 -not() -!!! test_not_cmd:3502 -not m foo -!!! test_not_masgn__24:4732 -!(a, b = foo) -!!! test_nth_ref:1016 -$10 -!!! test_numbered_args_after_27:7543 -m { _1 + _9 } -!!! test_numbered_args_after_27:7558 -m do _1 + _9 end -!!! test_numbered_args_after_27:7575 --> { _1 + _9} -!!! test_numbered_args_after_27:7590 --> do _1 + _9 end -!!! test_numparam_outside_block:7697 -class A; _1; end -!!! test_numparam_outside_block:7705 -module A; _1; end -!!! test_numparam_outside_block:7713 -class << foo; _1; end -!!! test_numparam_outside_block:7721 -def self.m; _1; end -!!! test_numparam_outside_block:7730 -_1 -!!! test_numparam_ruby_bug_19025:10696 -p { [_1 **2] } -!!! test_op_asgn:1620 -foo.a += 1 -!!! test_op_asgn:1630 -foo::a += 1 -!!! test_op_asgn:1636 -foo.A += 1 -!!! test_op_asgn_cmd:1644 -foo.a += m foo -!!! test_op_asgn_cmd:1650 -foo::a += m foo -!!! test_op_asgn_cmd:1656 -foo.A += m foo -!!! test_op_asgn_cmd:1668 -foo::A += m foo -!!! test_op_asgn_index:1678 -foo[0, 1] += 2 -!!! test_op_asgn_index_cmd:1692 -foo[0, 1] += m foo -!!! test_optarg:2088 -def f foo = 1; end -!!! test_optarg:2098 -def f(foo=1, bar=2); end -!!! test_or:4521 -foo or bar -!!! test_or:4527 -foo || bar -!!! test_or_asgn:1738 -foo.a ||= 1 -!!! test_or_asgn:1748 -foo[0, 1] ||= 2 -!!! test_parser_bug_272:6679 -a @b do |c|;end -!!! test_parser_bug_490:7336 -def m; class << self; class C; end; end; end -!!! test_parser_bug_490:7347 -def m; class << self; module M; end; end; end -!!! test_parser_bug_490:7358 -def m; class << self; A = nil; end; end -!!! test_parser_bug_507:7450 -m = -> *args do end -!!! test_parser_bug_518:7462 -class A < B -end -!!! test_parser_bug_525:7472 -m1 :k => m2 do; m3() do end; end -!!! test_parser_bug_604:7928 -m a + b do end -!!! test_parser_bug_640:445 -<<~FOO - baz\ - qux -FOO -!!! test_parser_bug_645:10073 --> (arg={}) {} -!!! test_parser_bug_830:10974 -/\(/ -!!! test_parser_bug_989:11684 - <<-HERE - content - HERE -!!! test_parser_drops_truncated_parts_of_squiggly_heredoc:10790 -<<~HERE - #{} -HERE -!!! test_parser_slash_slash_n_escaping_in_literals:7512:0 -'a\ -b' -!!! test_parser_slash_slash_n_escaping_in_literals:7512:1 -<<-'HERE' -a\ -b -HERE -!!! test_parser_slash_slash_n_escaping_in_literals:7512:2 -%q{a\ -b} -!!! test_parser_slash_slash_n_escaping_in_literals:7512:3 -"a\ -b" -!!! test_parser_slash_slash_n_escaping_in_literals:7512:4 -<<-"HERE" -a\ -b -HERE -!!! test_parser_slash_slash_n_escaping_in_literals:7512:5 -%{a\ -b} -!!! test_parser_slash_slash_n_escaping_in_literals:7512:6 -%Q{a\ -b} -!!! test_parser_slash_slash_n_escaping_in_literals:7512:7 -%w{a\ -b} -!!! test_parser_slash_slash_n_escaping_in_literals:7512:8 -%W{a\ -b} -!!! test_parser_slash_slash_n_escaping_in_literals:7512:9 -%i{a\ -b} -!!! test_parser_slash_slash_n_escaping_in_literals:7512:10 -%I{a\ -b} -!!! test_parser_slash_slash_n_escaping_in_literals:7512:11 -:'a\ -b' -!!! test_parser_slash_slash_n_escaping_in_literals:7512:12 -%s{a\ -b} -!!! test_parser_slash_slash_n_escaping_in_literals:7512:13 -:"a\ -b" -!!! test_parser_slash_slash_n_escaping_in_literals:7512:14 -/a\ -b/ -!!! test_parser_slash_slash_n_escaping_in_literals:7512:15 -%r{a\ -b} -!!! test_parser_slash_slash_n_escaping_in_literals:7512:16 -%x{a\ -b} -!!! test_parser_slash_slash_n_escaping_in_literals:7512:17 -`a\ -b` -!!! test_parser_slash_slash_n_escaping_in_literals:7512:18 -<<-`HERE` -a\ -b -HERE -!!! test_pattern_matching__FILE__LINE_literals:9760 - case [__FILE__, __LINE__ + 1, __ENCODING__] - in [__FILE__, __LINE__, __ENCODING__] - end -!!! test_pattern_matching_blank_else:9627 -case 1; in 2; 3; else; end -!!! test_pattern_matching_const_pattern:9490 -case foo; in A(1, 2) then true; end -!!! test_pattern_matching_const_pattern:9507 -case foo; in A(x:) then true; end -!!! test_pattern_matching_const_pattern:9523 -case foo; in A() then true; end -!!! test_pattern_matching_const_pattern:9538 -case foo; in A[1, 2] then true; end -!!! test_pattern_matching_const_pattern:9555 -case foo; in A[x:] then true; end -!!! test_pattern_matching_const_pattern:9571 -case foo; in A[] then true; end -!!! test_pattern_matching_constants:9456 -case foo; in A then true; end -!!! test_pattern_matching_constants:9466 -case foo; in A::B then true; end -!!! test_pattern_matching_constants:9477 -case foo; in ::A then true; end -!!! test_pattern_matching_else:9613 -case 1; in 2; 3; else; 4; end -!!! test_pattern_matching_explicit_array_match:8891 -case foo; in [x] then nil; end -!!! test_pattern_matching_explicit_array_match:8903 -case foo; in [x,] then nil; end -!!! test_pattern_matching_explicit_array_match:8915 -case foo; in [x, y] then true; end -!!! test_pattern_matching_explicit_array_match:8928 -case foo; in [x, y,] then true; end -!!! test_pattern_matching_explicit_array_match:8941 -case foo; in [x, y, *] then true; end -!!! test_pattern_matching_explicit_array_match:8955 -case foo; in [x, y, *z] then true; end -!!! test_pattern_matching_explicit_array_match:8969 -case foo; in [x, *y, z] then true; end -!!! test_pattern_matching_explicit_array_match:8983 -case foo; in [x, *, y] then true; end -!!! test_pattern_matching_explicit_array_match:8997 -case foo; in [*x, y] then true; end -!!! test_pattern_matching_explicit_array_match:9010 -case foo; in [*, x] then true; end -!!! test_pattern_matching_expr_in_paren:9443 -case foo; in (1) then true; end -!!! test_pattern_matching_hash:9025 -case foo; in {} then true; end -!!! test_pattern_matching_hash:9034 -case foo; in a: 1 then true; end -!!! test_pattern_matching_hash:9044 -case foo; in { a: 1 } then true; end -!!! test_pattern_matching_hash:9056 -case foo; in { a: 1, } then true; end -!!! test_pattern_matching_hash:9068 -case foo; in a: then true; end -!!! test_pattern_matching_hash:9080 -case foo; in **a then true; end -!!! test_pattern_matching_hash:9094 -case foo; in ** then true; end -!!! test_pattern_matching_hash:9106 -case foo; in a: 1, b: 2 then true; end -!!! test_pattern_matching_hash:9117 -case foo; in a:, b: then true; end -!!! test_pattern_matching_hash:9128 -case foo; in a: 1, _a:, ** then true; end -!!! test_pattern_matching_hash:9140 -case foo; - in {a: 1 - } - false - ; end -!!! test_pattern_matching_hash:9156 -case foo; - in {a: - 2} - false - ; end -!!! test_pattern_matching_hash:9171 -case foo; - in {Foo: 42 - } - false - ; end -!!! test_pattern_matching_hash:9186 -case foo; - in a: {b:}, c: - p c - ; end -!!! test_pattern_matching_hash:9203 -case foo; - in {a: - } - true - ; end -!!! test_pattern_matching_hash_with_string_keys:9242 -case foo; in "a": then true; end -!!! test_pattern_matching_hash_with_string_keys:9253 -case foo; in "#{ 'a' }": then true; end -!!! test_pattern_matching_hash_with_string_keys:9264 -case foo; in "#{ %q{a} }": then true; end -!!! test_pattern_matching_hash_with_string_keys:9275 -case foo; in "#{ %Q{a} }": then true; end -!!! test_pattern_matching_hash_with_string_keys:9288 -case foo; in "a": 1 then true; end -!!! test_pattern_matching_hash_with_string_keys:9297 -case foo; in "#{ 'a' }": 1 then true; end -!!! test_pattern_matching_hash_with_string_keys:9308 -case foo; in "#{ %q{a} }": 1 then true; end -!!! test_pattern_matching_hash_with_string_keys:9319 -case foo; in "#{ %Q{a} }": 1 then true; end -!!! test_pattern_matching_if_unless_modifiers:8753 -case foo; in x if true; nil; end -!!! test_pattern_matching_if_unless_modifiers:8767 -case foo; in x unless true; nil; end -!!! test_pattern_matching_implicit_array_match:8796 -case foo; in x, then nil; end -!!! test_pattern_matching_implicit_array_match:8806 -case foo; in *x then nil; end -!!! test_pattern_matching_implicit_array_match:8819 -case foo; in * then nil; end -!!! test_pattern_matching_implicit_array_match:8830 -case foo; in x, y then nil; end -!!! test_pattern_matching_implicit_array_match:8841 -case foo; in x, y, then nil; end -!!! test_pattern_matching_implicit_array_match:8852 -case foo; in x, *y, z then nil; end -!!! test_pattern_matching_implicit_array_match:8864 -case foo; in *x, y, z then nil; end -!!! test_pattern_matching_implicit_array_match:8876 -case foo; in 1, "a", [], {} then nil; end -!!! test_pattern_matching_keyword_variable:9370 -case foo; in self then true; end -!!! test_pattern_matching_lambda:9380 -case foo; in ->{ 42 } then true; end -!!! test_pattern_matching_match_alt:9587 -case foo; in 1 | 2 then true; end -!!! test_pattern_matching_match_as:9599 -case foo; in 1 => a then true; end -!!! test_pattern_matching_nil_pattern:9783 -case foo; in **nil then true; end -!!! test_pattern_matching_no_body:8745 -case foo; in 1; end -!!! test_pattern_matching_numbered_parameter:9654 -1.then { 1 in ^_1 } -!!! test_pattern_matching_pin_variable:8783 -case foo; in ^foo then nil; end -!!! test_pattern_matching_ranges:9393 -case foo; in 1..2 then true; end -!!! test_pattern_matching_ranges:9401 -case foo; in 1.. then true; end -!!! test_pattern_matching_ranges:9409 -case foo; in ..2 then true; end -!!! test_pattern_matching_ranges:9417 -case foo; in 1...2 then true; end -!!! test_pattern_matching_ranges:9425 -case foo; in 1... then true; end -!!! test_pattern_matching_ranges:9433 -case foo; in ...2 then true; end -!!! test_pattern_matching_single_line:9827 -1 => [a]; a -!!! test_pattern_matching_single_line:9839 -1 in [a]; a -!!! test_pattern_matching_single_line_allowed_omission_of_parentheses:9853 -[1, 2] => a, b; a -!!! test_pattern_matching_single_line_allowed_omission_of_parentheses:9868 -{a: 1} => a:; a -!!! test_pattern_matching_single_line_allowed_omission_of_parentheses:9883 -[1, 2] in a, b; a -!!! test_pattern_matching_single_line_allowed_omission_of_parentheses:9898 -{a: 1} in a:; a -!!! test_pattern_matching_single_line_allowed_omission_of_parentheses:9913 -{key: :value} in key: value; value -!!! test_pattern_matching_single_line_allowed_omission_of_parentheses:9930 -{key: :value} => key: value; value -!!! test_pattern_matching_single_match:8730 -case foo; in x then x; end -!!! test_pin_expr:10800 -case foo; in ^(42) then nil; end -!!! test_pin_expr:10814 -case foo; in { foo: ^(42) } then nil; end -!!! test_pin_expr:10831 -case foo; in ^(0+0) then nil; end -!!! test_pin_expr:10847 -case foo; in ^@a; end -!!! test_pin_expr:10856 -case foo; in ^@@TestPatternMatching; end -!!! test_pin_expr:10865 -case foo; in ^$TestPatternMatching; end -!!! test_pin_expr:10874 -case foo; in ^(1 -); end -!!! test_postexe:5618 -END { 1 } -!!! test_preexe:5599 -BEGIN { 1 } -!!! test_procarg0:2817 -m { |foo| } -!!! test_procarg0:2826 -m { |(foo, bar)| } -!!! test_procarg0_legacy:2796 -f{ |a| } -!!! test_range_endless:883 -1.. -!!! test_range_endless:891 -1... -!!! test_range_exclusive:875 -1...2 -!!! test_range_inclusive:867 -1..2 -!!! test_rational:144 -42r -!!! test_rational:150 -42.1r -!!! test_redo:5310 -redo -!!! test_regex_interp:553 -/foo#{bar}baz/ -!!! test_regex_plain:543 -/source/im -!!! test_resbody_list:5530 -begin; meth; rescue Exception; bar; end -!!! test_resbody_list_mrhs:5543 -begin; meth; rescue Exception, foo; bar; end -!!! test_resbody_list_var:5576 -begin; meth; rescue foo => ex; bar; end -!!! test_resbody_var:5558 -begin; meth; rescue => ex; bar; end -!!! test_resbody_var:5566 -begin; meth; rescue => @ex; bar; end -!!! test_rescue:5320 -begin; meth; rescue; foo; end -!!! test_rescue_else:5335 -begin; meth; rescue; foo; else; bar; end -!!! test_rescue_else_ensure:5434 -begin; meth; rescue; baz; else foo; ensure; bar end -!!! test_rescue_ensure:5418 -begin; meth; rescue; baz; ensure; bar; end -!!! test_rescue_in_lambda_block:7113 --> do rescue; end -!!! test_rescue_mod:5451 -meth rescue bar -!!! test_rescue_mod_asgn:5463 -foo = meth rescue bar -!!! test_rescue_mod_masgn:5477 -foo, bar = meth rescue [1, 2] -!!! test_rescue_mod_op_assign:5497 -foo += meth rescue bar -!!! test_rescue_without_begin_end:5513 -meth do; foo; rescue; bar; end -!!! test_restarg_named:2108 -def f(*foo); end -!!! test_restarg_unnamed:2118 -def f(*); end -!!! test_retry:5589 -retry -!!! test_return:5216 -return(foo) -!!! test_return:5230 -return foo -!!! test_return:5236 -return() -!!! test_return:5243 -return -!!! test_return_block:5251 -return fun foo do end -!!! test_ruby_bug_10279:6056 -{a: if true then 42 end} -!!! test_ruby_bug_10653:6066 -true ? 1.tap do |n| p n end : 0 -!!! test_ruby_bug_10653:6096 -false ? raise {} : tap {} -!!! test_ruby_bug_10653:6109 -false ? raise do end : tap do end -!!! test_ruby_bug_11107:6124 -p ->() do a() do end end -!!! test_ruby_bug_11380:6136 -p -> { :hello }, a: 1 do end -!!! test_ruby_bug_11873:6504 -a b{c d}, "x" do end -!!! test_ruby_bug_11873:6518 -a b(c d), "x" do end -!!! test_ruby_bug_11873:6531 -a b{c(d)}, "x" do end -!!! test_ruby_bug_11873:6545 -a b(c(d)), "x" do end -!!! test_ruby_bug_11873:6558 -a b{c d}, /x/ do end -!!! test_ruby_bug_11873:6572 -a b(c d), /x/ do end -!!! test_ruby_bug_11873:6585 -a b{c(d)}, /x/ do end -!!! test_ruby_bug_11873:6599 -a b(c(d)), /x/ do end -!!! test_ruby_bug_11873:6612 -a b{c d}, /x/m do end -!!! test_ruby_bug_11873:6626 -a b(c d), /x/m do end -!!! test_ruby_bug_11873:6639 -a b{c(d)}, /x/m do end -!!! test_ruby_bug_11873:6653 -a b(c(d)), /x/m do end -!!! test_ruby_bug_11873_a:6168:0 -a b{c d}, :e do end -!!! test_ruby_bug_11873_a:6168:1 -a b{c d}, 1 do end -!!! test_ruby_bug_11873_a:6168:2 -a b{c d}, 1.0 do end -!!! test_ruby_bug_11873_a:6168:3 -a b{c d}, 1.0r do end -!!! test_ruby_bug_11873_a:6168:4 -a b{c d}, 1.0i do end -!!! test_ruby_bug_11873_a:6173:0 -a b{c(d)}, :e do end -!!! test_ruby_bug_11873_a:6173:1 -a b{c(d)}, 1 do end -!!! test_ruby_bug_11873_a:6173:2 -a b{c(d)}, 1.0 do end -!!! test_ruby_bug_11873_a:6173:3 -a b{c(d)}, 1.0r do end -!!! test_ruby_bug_11873_a:6173:4 -a b{c(d)}, 1.0i do end -!!! test_ruby_bug_11873_a:6187:0 -a b(c d), :e do end -!!! test_ruby_bug_11873_a:6187:1 -a b(c d), 1 do end -!!! test_ruby_bug_11873_a:6187:2 -a b(c d), 1.0 do end -!!! test_ruby_bug_11873_a:6187:3 -a b(c d), 1.0r do end -!!! test_ruby_bug_11873_a:6187:4 -a b(c d), 1.0i do end -!!! test_ruby_bug_11873_a:6192:0 -a b(c(d)), :e do end -!!! test_ruby_bug_11873_a:6192:1 -a b(c(d)), 1 do end -!!! test_ruby_bug_11873_a:6192:2 -a b(c(d)), 1.0 do end -!!! test_ruby_bug_11873_a:6192:3 -a b(c(d)), 1.0r do end -!!! test_ruby_bug_11873_a:6192:4 -a b(c(d)), 1.0i do end -!!! test_ruby_bug_11873_b:6201 -p p{p(p);p p}, tap do end -!!! test_ruby_bug_11989:6220 -p <<~"E" - x\n y -E -!!! test_ruby_bug_11990:6229 -p <<~E " y" - x -E -!!! test_ruby_bug_12073:6240 -a = 1; a b: 1 -!!! test_ruby_bug_12073:6253 -def foo raise; raise A::B, ''; end -!!! test_ruby_bug_12402:6267 -foo = raise(bar) rescue nil -!!! test_ruby_bug_12402:6278 -foo += raise(bar) rescue nil -!!! test_ruby_bug_12402:6290 -foo[0] += raise(bar) rescue nil -!!! test_ruby_bug_12402:6304 -foo.m += raise(bar) rescue nil -!!! test_ruby_bug_12402:6317 -foo::m += raise(bar) rescue nil -!!! test_ruby_bug_12402:6330 -foo.C += raise(bar) rescue nil -!!! test_ruby_bug_12402:6343 -foo::C ||= raise(bar) rescue nil -!!! test_ruby_bug_12402:6356 -foo = raise bar rescue nil -!!! test_ruby_bug_12402:6367 -foo += raise bar rescue nil -!!! test_ruby_bug_12402:6379 -foo[0] += raise bar rescue nil -!!! test_ruby_bug_12402:6393 -foo.m += raise bar rescue nil -!!! test_ruby_bug_12402:6406 -foo::m += raise bar rescue nil -!!! test_ruby_bug_12402:6419 -foo.C += raise bar rescue nil -!!! test_ruby_bug_12402:6432 -foo::C ||= raise bar rescue nil -!!! test_ruby_bug_12669:6447 -a = b = raise :x -!!! test_ruby_bug_12669:6456 -a += b = raise :x -!!! test_ruby_bug_12669:6465 -a = b += raise :x -!!! test_ruby_bug_12669:6474 -a += b += raise :x -!!! test_ruby_bug_12686:6485 -f (g rescue nil) -!!! test_ruby_bug_13547:7203 -meth[] {} -!!! test_ruby_bug_14690:7435 -let () { m(a) do; end } -!!! test_ruby_bug_15789:7807 -m ->(a = ->{_1}) {a} -!!! test_ruby_bug_15789:7821 -m ->(a: ->{_1}) {a} -!!! test_ruby_bug_9669:6040 -def a b: -return -end -!!! test_ruby_bug_9669:6046 -o = { -a: -1 -} -!!! test_sclass:1898 -class << foo; nil; end -!!! test_self:966 -self -!!! test_send_attr_asgn:3542 -foo.a = 1 -!!! test_send_attr_asgn:3550 -foo::a = 1 -!!! test_send_attr_asgn:3558 -foo.A = 1 -!!! test_send_attr_asgn:3566 -foo::A = 1 -!!! test_send_attr_asgn_conditional:3792 -a&.b = 1 -!!! test_send_binary_op:3322 -foo + 1 -!!! test_send_binary_op:3328 -foo - 1 -!!! test_send_binary_op:3332 -foo * 1 -!!! test_send_binary_op:3336 -foo / 1 -!!! test_send_binary_op:3340 -foo % 1 -!!! test_send_binary_op:3344 -foo ** 1 -!!! test_send_binary_op:3348 -foo | 1 -!!! test_send_binary_op:3352 -foo ^ 1 -!!! test_send_binary_op:3356 -foo & 1 -!!! test_send_binary_op:3360 -foo <=> 1 -!!! test_send_binary_op:3364 -foo < 1 -!!! test_send_binary_op:3368 -foo <= 1 -!!! test_send_binary_op:3372 -foo > 1 -!!! test_send_binary_op:3376 -foo >= 1 -!!! test_send_binary_op:3380 -foo == 1 -!!! test_send_binary_op:3390 -foo != 1 -!!! test_send_binary_op:3396 -foo === 1 -!!! test_send_binary_op:3400 -foo =~ 1 -!!! test_send_binary_op:3410 -foo !~ 1 -!!! test_send_binary_op:3416 -foo << 1 -!!! test_send_binary_op:3420 -foo >> 1 -!!! test_send_block_chain_cmd:3215 -meth 1 do end.fun bar -!!! test_send_block_chain_cmd:3226 -meth 1 do end.fun(bar) -!!! test_send_block_chain_cmd:3239 -meth 1 do end::fun bar -!!! test_send_block_chain_cmd:3250 -meth 1 do end::fun(bar) -!!! test_send_block_chain_cmd:3263 -meth 1 do end.fun bar do end -!!! test_send_block_chain_cmd:3275 -meth 1 do end.fun(bar) {} -!!! test_send_block_chain_cmd:3287 -meth 1 do end.fun {} -!!! test_send_block_conditional:3800 -foo&.bar {} -!!! test_send_call:3762 -foo.(1) -!!! test_send_call:3772 -foo::(1) -!!! test_send_conditional:3784 -a&.b -!!! test_send_index:3576 -foo[1, 2] -!!! test_send_index_asgn:3605 -foo[1, 2] = 3 -!!! test_send_index_asgn_kwarg:3629 -foo[:kw => arg] = 3 -!!! test_send_index_asgn_kwarg_legacy:3642 -foo[:kw => arg] = 3 -!!! test_send_index_asgn_legacy:3617 -foo[1, 2] = 3 -!!! test_send_index_cmd:3598 -foo[m bar] -!!! test_send_index_legacy:3587 -foo[1, 2] -!!! test_send_lambda:3656 -->{ } -!!! test_send_lambda:3666 --> * { } -!!! test_send_lambda:3677 --> do end -!!! test_send_lambda_args:3689 -->(a) { } -!!! test_send_lambda_args:3703 --> (a) { } -!!! test_send_lambda_args_noparen:3727 --> a: 1 { } -!!! test_send_lambda_args_noparen:3736 --> a: { } -!!! test_send_lambda_args_shadow:3714 -->(a; foo, bar) { } -!!! test_send_lambda_legacy:3748 -->{ } -!!! test_send_op_asgn_conditional:3811 -a&.b &&= 1 -!!! test_send_plain:3119 -foo.fun -!!! test_send_plain:3126 -foo::fun -!!! test_send_plain:3133 -foo::Fun() -!!! test_send_plain_cmd:3142 -foo.fun bar -!!! test_send_plain_cmd:3149 -foo::fun bar -!!! test_send_plain_cmd:3156 -foo::Fun bar -!!! test_send_self:3058 -fun -!!! test_send_self:3064 -fun! -!!! test_send_self:3070 -fun(1) -!!! test_send_self_block:3080 -fun { } -!!! test_send_self_block:3084 -fun() { } -!!! test_send_self_block:3088 -fun(1) { } -!!! test_send_self_block:3092 -fun do end -!!! test_send_unary_op:3426 --foo -!!! test_send_unary_op:3432 -+foo -!!! test_send_unary_op:3436 -~foo -!!! test_slash_newline_in_heredocs:7371 -<<~E - 1 \ - 2 - 3 -E -!!! test_slash_newline_in_heredocs:7379 -<<-E - 1 \ - 2 - 3 -E -!!! test_space_args_arg:4192 -fun (1) -!!! test_space_args_arg_block:4206 -fun (1) {} -!!! test_space_args_arg_block:4220 -foo.fun (1) {} -!!! test_space_args_arg_block:4236 -foo::fun (1) {} -!!! test_space_args_arg_call:4258 -fun (1).to_i -!!! test_space_args_arg_newline:4198 -fun (1 -) -!!! test_space_args_block:4490 -fun () {} -!!! test_space_args_cmd:4185 -fun (f bar) -!!! test_string___FILE__:243 -__FILE__ -!!! test_string_concat:228 -"foo#@a" "bar" -!!! test_string_dvar:217 -"#@a #@@a #$a" -!!! test_string_interp:202 -"foo#{bar}baz" -!!! test_string_plain:186 -'foobar' -!!! test_string_plain:193 -%q(foobar) -!!! test_super:3867 -super(foo) -!!! test_super:3875 -super foo -!!! test_super:3881 -super() -!!! test_super_block:3899 -super foo, bar do end -!!! test_super_block:3905 -super do end -!!! test_symbol_interp:486 -:"foo#{bar}baz" -!!! test_symbol_plain:471 -:foo -!!! test_symbol_plain:477 -:'foo' -!!! test_ternary:4665 -foo ? 1 : 2 -!!! test_ternary_ambiguous_symbol:4674 -t=1;(foo)?t:T -!!! test_trailing_forward_arg:8237 -def foo(a, b, ...); bar(a, 42, ...); end -!!! test_true:91 -true -!!! test_unary_num_pow_precedence:3519 -+2.0 ** 10 -!!! test_unary_num_pow_precedence:3526 --2 ** 10 -!!! test_unary_num_pow_precedence:3533 --2.0 ** 10 -!!! test_undef:2017 -undef foo, :bar, :"foo#{1}" -!!! test_unless:4589 -unless foo then bar; end -!!! test_unless:4597 -unless foo; bar; end -!!! test_unless_else:4633 -unless foo then bar; else baz; end -!!! test_unless_else:4642 -unless foo; bar; else baz; end -!!! test_unless_mod:4606 -bar unless foo -!!! test_until:5080 -until foo do meth end -!!! test_until:5087 -until foo; meth end -!!! test_until_mod:5095 -meth until foo -!!! test_until_post:5110 -begin meth end until foo -!!! test_var_and_asgn:1728 -a &&= 1 -!!! test_var_op_asgn:1512 -a += 1 -!!! test_var_op_asgn:1518 -@a |= 1 -!!! test_var_op_asgn:1524 -@@var |= 10 -!!! test_var_op_asgn:1528 -def a; @@var |= 10; end -!!! test_var_op_asgn_cmd:1535 -foo += m foo -!!! test_var_or_asgn:1720 -a ||= 1 -!!! test_when_multi:5027 -case foo; when 'bar', 'baz'; bar; end -!!! test_when_splat:5036 -case foo; when 1, *baz; bar; when *foo; end -!!! test_when_then:5015 -case foo; when 'bar' then bar; end -!!! test_while:5056 -while foo do meth end -!!! test_while:5064 -while foo; meth end -!!! test_while_mod:5073 -meth while foo -!!! test_while_post:5102 -begin meth end while foo -!!! test_xstring_interp:526 -`foo#{bar}baz` -!!! test_xstring_plain:517 -`foobar` -!!! test_yield:3915 -yield(foo) -!!! test_yield:3923 -yield foo -!!! test_yield:3929 -yield() -!!! test_yield:3937 -yield -!!! test_zsuper:3891 -super diff --git a/test/translation/parser_test.rb b/test/translation/parser_test.rb deleted file mode 100644 index dd88322e..00000000 --- a/test/translation/parser_test.rb +++ /dev/null @@ -1,141 +0,0 @@ -# frozen_string_literal: true - -require_relative "../test_helper" -require "parser/current" - -Parser::Builders::Default.modernize - -module SyntaxTree - module Translation - class ParserTest < Minitest::Test - skips = %w[ - test_args_assocs_legacy:4041 - test_args_assocs:4091 - test_args_assocs:4091 - test_break_block:5204 - test_break:5169 - test_break:5183 - test_break:5189 - test_break:5196 - test_control_meta_escape_chars_in_regexp__since_31:* - test_dedenting_heredoc:336 - test_dedenting_heredoc:392 - test_dedenting_heredoc:401 - test_forwarded_argument_with_kwrestarg:11332 - test_forwarded_argument_with_restarg:11267 - test_forwarded_kwrestarg_with_additional_kwarg:11306 - test_forwarded_kwrestarg:11287 - test_forwarded_restarg:11249 - test_hash_pair_value_omission:10364 - test_hash_pair_value_omission:10376 - test_if_while_after_class__since_32:11374 - test_if_while_after_class__since_32:11384 - test_kwoptarg_with_kwrestarg_and_forwarded_args:11482 - test_lvar_injecting_match:3819 - test_newline_in_hash_argument:11427 - test_next_block:5298 - test_next:5263 - test_next:5277 - test_next:5283 - test_next:5290 - test_next:5290 - test_parser_slash_slash_n_escaping_in_literals:* - test_pattern_matching_explicit_array_match:8903 - test_pattern_matching_explicit_array_match:8928 - test_pattern_matching_expr_in_paren:9443 - test_pattern_matching_hash_with_string_keys:* - test_pattern_matching_hash_with_string_keys:9264 - test_pattern_matching_hash:9186 - test_pattern_matching_implicit_array_match:8796 - test_pattern_matching_implicit_array_match:8841 - test_pattern_matching_numbered_parameter:9654 - test_pattern_matching_single_line_allowed_omission_of_parentheses:9868 - test_pattern_matching_single_line_allowed_omission_of_parentheses:9898 - test_redo:5310 - test_retry:5589 - test_send_index_asgn_kwarg_legacy:3642 - test_send_index_asgn_kwarg_legacy:3642 - test_send_index_asgn_kwarg:3629 - test_send_index_asgn_kwarg:3629 - test_slash_newline_in_heredocs:7379 - test_unary_num_pow_precedence:3519 - test_yield:3915 - test_yield:3923 - test_yield:3929 - test_yield:3937 - ] - - if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.1.0") - skips.push( - "test_endless_method_forwarded_args_legacy:10139", - "test_forward_arg_with_open_args:11114", - "test_forward_arg:8090", - "test_forward_args_legacy:8054", - "test_forward_args_legacy:8066", - "test_forward_args_legacy:8078", - "test_pattern_matching_hash:*", - "test_pattern_matching_single_line:9839", - "test_trailing_forward_arg:8237" - ) - end - - File - .foreach(File.expand_path("parser.txt", __dir__), chomp: true) - .slice_before { |line| line.start_with?("!!!") } - .each do |(prefix, *lines)| - name = prefix[4..] - next if skips.any? { |skip| File.fnmatch?(skip, name) } - - define_method(name) { assert_parses("#{lines.join("\n")}\n") } - end - - private - - def assert_parses(source) - parser = ::Parser::CurrentRuby.default_parser - parser.diagnostics.consumer = ->(*) {} - - buffer = ::Parser::Source::Buffer.new("(string)", 1) - buffer.source = source - - expected = - begin - parser.parse(buffer) - rescue ::Parser::SyntaxError - # We can get a syntax error if we're parsing a fixture that was - # designed for a later Ruby version but we're running an earlier - # Ruby version. In this case we can just return early from the test. - end - - return if expected.nil? - node = SyntaxTree.parse(source) - assert_equal expected, SyntaxTree::Translation.to_parser(node, buffer) - end - end - end -end - -if ENV["PARSER_LOCATION"] - # 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 do - 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 - 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 do - def ==(other) - super && (location == other.location) - end - end - ) -end