$TESTING = true require 'test/unit/testcase' require 'sexp_processor' # for deep_clone require 'unique' # key: # wwtt = what were they thinking? class Examples attr_reader :reader attr_writer :writer def a_method(x); x+1; end alias an_alias a_method define_method(:bmethod_noargs) do x + 1 end define_method(:unsplatted) do |x| x + 1 end define_method :splatted do |*args| y = args.first y + 42 end define_method :dmethod_added, instance_method(:a_method) if RUBY_VERSION < "1.9" end class ParseTreeTestCase < Test::Unit::TestCase attr_accessor :processor # to be defined by subclass def self.testcase_order; @@testcase_order; end def self.testcases; @@testcases; end def setup super @processor = nil Unique.reset end def self.add_test name, data, klass = self.name[4..-1] name = name.to_s klass = klass.to_s if testcases.has_key? name then if testcases[name].has_key? klass then warn "testcase #{klass}##{name} already has data" else testcases[name][klass] = data end else warn "testcase #{name} does not exist" end end def self.unsupported_tests *tests tests.flatten.each do |name| add_test name, :unsupported end end @@testcase_order = %w(Ruby ParseTree) @@testcases = { "alias" => { "Ruby" => "class X\n alias :y :x\nend", "ParseTree" => [:class, :X, nil, [:scope, [:alias, [:lit, :y], [:lit, :x]]]], "Ruby2Ruby" => "class X\n alias_method :y, :x\nend", }, "alias_ugh" => { "Ruby" => "class X\n alias y x\nend", "ParseTree" => [:class, :X, nil, [:scope, [:alias, [:lit, :y], [:lit, :x]]]], "Ruby2Ruby" => "class X\n alias_method :y, :x\nend", }, "and" => { "Ruby" => "(a and b)", "ParseTree" => [:and, [:vcall, :a], [:vcall, :b]], }, "argscat_inside" => { "Ruby" => "a = [b, *c]", "ParseTree" => [:lasgn, :a, [:argscat, [:array, [:vcall, :b]], [:vcall, :c]]], "Ruby2Ruby" => "a = b, *c", }, "argscat_svalue" => { "Ruby" => "a = b, c, *d", "ParseTree" => [:lasgn, :a, [:svalue, [:argscat, [:array, [:vcall, :b], [:vcall, :c]], [:vcall, :d]]]], }, "argspush" => { "Ruby" => "a[*b] = c", "ParseTree" => [:attrasgn, [:vcall, :a], :[]=, [:argspush, [:splat, [:vcall, :b]], [:vcall, :c]]], }, "array" => { "Ruby" => "[1, :b, \"c\"]", "ParseTree" => [:array, [:lit, 1], [:lit, :b], [:str, "c"]], }, "array_pct_W" => { "Ruby" => "%W[--remove #\{@gem_repo}]", "ParseTree" => [:array, [:str, "--remove"], [:dstr, "", [:evstr, [:ivar, :@gem_repo]]]], "Ruby2Ruby" => "[\"--remove\", \"#\{@gem_repo}\"]", }, "attrasgn" => { "Ruby" => "y = 0\n42.method = y\n", "ParseTree" => [:block, [:lasgn, :y, [:lit, 0]], [:attrasgn, [:lit, 42], :method=, [:array, [:lvar, :y]]]], }, "attrasgn_index_equals" => { "Ruby" => "a[42] = 24", "ParseTree" => [:attrasgn, [:vcall, :a], :[]=, [:array, [:lit, 42], [:lit, 24]]], }, "attrset" => { "Ruby" => [Examples, :writer=], "ParseTree" => [:defn, :writer=, [:attrset, :@writer]], "Ruby2Ruby" => "attr_writer :writer" }, "back_ref" => { "Ruby" => "[$&, $`, $', $+]", "ParseTree" => [:array, [:back_ref, :&], [:back_ref, "`".intern], # symbol was fucking up emacs [:back_ref, "'".intern], # s->e [:back_ref, :+]], }, "begin" => { "Ruby" => "begin\n (1 + 1)\nend", "ParseTree" => [:begin, [:call, [:lit, 1], :+, [:array, [:lit, 1]]]], }, "begin_def" => { "Ruby" => "def m\n begin\n\n end\nend", "ParseTree" => [:defn, :m, [:scope, [:block, [:args], [:nil]]]], "Ruby2Ruby" => "def m\n # do nothing\nend", }, "begin_rescue_ensure" => { "Ruby" => "begin\nrescue\n # do nothing\nensure\n nil\nend", "ParseTree" => [:begin, [:ensure, [:rescue, [:resbody, nil]], [:nil]]] }, "begin_rescue_twice" => { # testing block/begin processing really "Ruby" => "begin\nrescue => mes\n # do nothing\nend\nbegin\nrescue => mes\n # do nothing\nend\n", "ParseTree" => [:block, [:rescue, [:resbody, nil, [:lasgn, :mes, [:gvar, :$!]]]], [:begin, [:rescue, [:resbody, nil, [:lasgn, :mes, [:gvar, :$!]]]]]], }, "block_lasgn" => { "Ruby" => "x = (y = 1\n(y + 2))", "ParseTree" => [:lasgn, :x, [:block, [:lasgn, :y, [:lit, 1]], [:call, [:lvar, :y], :+, [:array, [:lit, 2]]]]], }, "block_mystery_block" => { # FIX: I don't like that extra return "Ruby" => "a(b) do\n if b then\n true\n else\n c = false\n d { |x| c = true }\n c\n \n end\nend", "ParseTree" => [:iter, [:fcall, :a, [:array, [:vcall, :b]]], nil, [:block, [:dasgn_curr, :c], [:if, [:vcall, :b], [:true], [:block, [:dasgn_curr, :c, [:false]], [:iter, [:fcall, :d], [:dasgn_curr, :x], [:dasgn, :c, [:true]]], [:dvar, :c]]]]], }, "block_pass_args_and_splat" => { "Ruby" => "def blah(*args, &block)\n other(42, *args, &block)\nend", "ParseTree" => [:defn, :blah, [:scope, [:block, [:args, "*args".intern], [:block_arg, :block], [:block_pass, [:lvar, :block], [:fcall, :other, [:argscat, [:array, [:lit, 42]], [:lvar, :args]]]]]]], }, "block_pass_call_0" => { "Ruby" => "a.b(&c)", "ParseTree" => [:block_pass, [:vcall, :c], [:call, [:vcall, :a], :b]], }, "block_pass_call_1" => { "Ruby" => "a.b(4, &c)", "ParseTree" => [:block_pass, [:vcall, :c], [:call, [:vcall, :a], :b, [:array, [:lit, 4]]]], }, "block_pass_call_n" => { "Ruby" => "a.b(1, 2, 3, &c)", "ParseTree" => [:block_pass, [:vcall, :c], [:call, [:vcall, :a], :b, [:array, [:lit, 1], [:lit, 2], [:lit, 3]]]], }, "block_pass_fcall_0" => { "Ruby" => "a(&b)", "ParseTree" => [:block_pass, [:vcall, :b], [:fcall, :a]], }, "block_pass_fcall_1" => { "Ruby" => "a(4, &b)", "ParseTree" => [:block_pass, [:vcall, :b], [:fcall, :a, [:array, [:lit, 4]]]], }, "block_pass_fcall_n" => { "Ruby" => "a(1, 2, 3, &b)", "ParseTree" => [:block_pass, [:vcall, :b], [:fcall, :a, [:array, [:lit, 1], [:lit, 2], [:lit, 3]]]], }, "block_pass_omgwtf" => { "Ruby" => "define_attr_method(:x, :sequence_name, &Proc.new { |*args| nil })", "ParseTree" => [:block_pass, [:iter, [:call, [:const, :Proc], :new], [:masgn, [:dasgn_curr, :args]], [:nil]], [:fcall, :define_attr_method, [:array, [:lit, :x], [:lit, :sequence_name]]]], }, "block_pass_splat" => { "Ruby" => "def blah(*args, &block)\n other(*args, &block)\nend", "ParseTree" => [:defn, :blah, [:scope, [:block, [:args, "*args".intern], [:block_arg, :block], [:block_pass, [:lvar, :block], [:fcall, :other, [:splat, [:lvar, :args]]]]]]], }, "block_pass_thingy" => { "Ruby" => "r.read_body(dest, &block)", "ParseTree" => [:block_pass, [:vcall, :block], [:call, [:vcall, :r], :read_body, [:array, [:vcall, :dest]]]], }, "block_stmt_after" => { "Ruby" => "def f\n begin\n b\n rescue\n c\n end\n\n d\nend", "ParseTree" => [:defn, :f, [:scope, [:block, [:args], [:rescue, [:vcall, :b], [:resbody, nil, [:vcall, :c]]], [:vcall, :d]]]], "Ruby2Ruby" => "def f\n b rescue c\n d\nend", }, "block_stmt_before" => { "Ruby" => "def f\n a\n begin\n b\n rescue\n c\n end\nend", "ParseTree" => [:defn, :f, [:scope, [:block, [:args], [:vcall, :a], [:begin, [:rescue, [:vcall, :b], [:resbody, nil, [:vcall, :c]]]]]]], }, "block_stmt_both" => { "Ruby" => "def f\n a\n begin\n b\n rescue\n c\n end\n d\nend", "ParseTree" => [:defn, :f, [:scope, [:block, [:args], [:vcall, :a], [:rescue, [:vcall, :b], [:resbody, nil, [:vcall, :c]]], [:vcall, :d]]]], "Ruby2Ruby" => "def f\n a\n b rescue c\n d\nend", }, "bmethod" => { "Ruby" => [Examples, :unsplatted], "ParseTree" => [:defn, :unsplatted, [:bmethod, [:dasgn_curr, :x], [:call, [:dvar, :x], :+, [:array, [:lit, 1]]]]], "Ruby2Ruby" => "def unsplatted(x)\n (x + 1)\nend" }, "bmethod_noargs" => { "Ruby" => [Examples, :bmethod_noargs], "ParseTree" => [:defn, :bmethod_noargs, [:bmethod, nil, [:call, [:vcall, :x], "+".intern, [:array, [:lit, 1]]]]], "Ruby2Ruby" => "def bmethod_noargs\n (x + 1)\nend" }, "bmethod_splat" => { "Ruby" => [Examples, :splatted], "ParseTree" => [:defn, :splatted, [:bmethod, [:masgn, [:dasgn_curr, :args]], [:block, [:dasgn_curr, :y, [:call, [:dvar, :args], :first]], [:call, [:dvar, :y], :+, [:array, [:lit, 42]]]]]], "Ruby2Ruby" => "def splatted(*args)\n y = args.first\n (y + 42)\nend", }, "break" => { "Ruby" => "loop { break if true }", "ParseTree" => [:iter, [:fcall, :loop], nil, [:if, [:true], [:break], nil]], }, "break_arg" => { "Ruby" => "loop { break 42 if true }", "ParseTree" => [:iter, [:fcall, :loop], nil, [:if, [:true], [:break, [:lit, 42]], nil]], }, "call" => { "Ruby" => "self.method", "ParseTree" => [:call, [:self], :method], }, "call_arglist" => { "Ruby" => "o.puts(42)", "ParseTree" => [:call, [:vcall, :o], :puts, [:array, [:lit, 42]]], }, "call_arglist_hash" => { "Ruby" => "o.m(:a => 1, :b => 2)", "ParseTree" => [:call, [:vcall, :o], :m, [:array, [:hash, [:lit, :a], [:lit, 1], [:lit, :b], [:lit, 2]]]], }, "call_arglist_norm_hash" => { "Ruby" => "o.m(42, :a => 1, :b => 2)", "ParseTree" => [:call, [:vcall, :o], :m, [:array, [:lit, 42], [:hash, [:lit, :a], [:lit, 1], [:lit, :b], [:lit, 2]]]], }, "call_arglist_norm_hash_splat" => { "Ruby" => "o.m(42, :a => 1, :b => 2, *c)", "ParseTree" => [:call, [:vcall, :o], :m, [:argscat, [:array, [:lit, 42], [:hash, [:lit, :a], [:lit, 1], [:lit, :b], [:lit, 2]]], [:vcall, :c]]], }, "call_command" => { "Ruby" => "1.b(c)", "ParseTree" => [:call, [:lit, 1], :b, [:array, [:vcall, :c]]], }, "call_expr" => { "Ruby" => "(v = (1 + 1)).zero?", "ParseTree" => [:call, [:lasgn, :v, [:call, [:lit, 1], :+, [:array, [:lit, 1]]]], :zero?], }, "call_index" => { # see attrasgn_index_equals for opposite "Ruby" => "a[42]", "ParseTree" => [:call, [:vcall, :a], :[], [:array, [:lit, 42]]], }, "call_index_no_args" => { "Ruby" => "a[]", "ParseTree" => [:call, [:vcall, :a], :[]], }, "call_unary_neg" => { "Ruby" => "-2**31", "ParseTree" => [:call, [:call, [:lit, 2], :**, [:array, [:lit, 31]]], :-@], "Ruby2Ruby" => "-(2 ** 31)", }, "case" => { "Ruby" => "var = 2\nresult = \"\"\ncase var\nwhen 1 then\n puts(\"something\")\n result = \"red\"\nwhen 2, 3 then\n result = \"yellow\"\nwhen 4 then\n # do nothing\nelse\n result = \"green\"\nend\ncase result\nwhen \"red\" then\n var = 1\nwhen \"yellow\" then\n var = 2\nwhen \"green\" then\n var = 3\nelse\n # do nothing\nend\n", "ParseTree" => [:block, [:lasgn, :var, [:lit, 2]], [:lasgn, :result, [:str, ""]], [:case, [:lvar, :var], [:when, [:array, [:lit, 1]], [:block, [:fcall, :puts, [:array, [:str, "something"]]], [:lasgn, :result, [:str, "red"]]]], [:when, [:array, [:lit, 2], [:lit, 3]], [:lasgn, :result, [:str, "yellow"]]], [:when, [:array, [:lit, 4]], nil], [:lasgn, :result, [:str, "green"]]], [:case, [:lvar, :result], [:when, [:array, [:str, "red"]], [:lasgn, :var, [:lit, 1]]], [:when, [:array, [:str, "yellow"]], [:lasgn, :var, [:lit, 2]]], [:when, [:array, [:str, "green"]], [:lasgn, :var, [:lit, 3]]], nil]] }, "case_nested" => { "Ruby" => "var1 = 1\nvar2 = 2\nresult = nil\ncase var1\nwhen 1 then\n case var2\n when 1 then\n result = 1\n when 2 then\n result = 2\n else\n result = 3\n end\nwhen 2 then\n case var2\n when 1 then\n result = 4\n when 2 then\n result = 5\n else\n result = 6\n end\nelse\n result = 7\nend\n", "ParseTree" => [:block, [:lasgn, :var1, [:lit, 1]], [:lasgn, :var2, [:lit, 2]], [:lasgn, :result, [:nil]], [:case, [:lvar, :var1], [:when, [:array, [:lit, 1]], [:case, [:lvar, :var2], [:when, [:array, [:lit, 1]], [:lasgn, :result, [:lit, 1]]], [:when, [:array, [:lit, 2]], [:lasgn, :result, [:lit, 2]]], [:lasgn, :result, [:lit, 3]]]], [:when, [:array, [:lit, 2]], [:case, [:lvar, :var2], [:when, [:array, [:lit, 1]], [:lasgn, :result, [:lit, 4]]], [:when, [:array, [:lit, 2]], [:lasgn, :result, [:lit, 5]]], [:lasgn, :result, [:lit, 6]]]], [:lasgn, :result, [:lit, 7]]]] }, "case_nested_inner_no_expr" => { "Ruby" => "case a\nwhen b then\n case\n when (d and e) then\n f\n else\n # do nothing\n end\nelse\n # do nothing\nend", "ParseTree" => [:case, [:vcall, :a], [:when, [:array, [:vcall, :b]], [:case, nil, [:when, [:array, [:and, [:vcall, :d], [:vcall, :e]]], [:vcall, :f]], nil]], nil], }, "case_no_expr" => { # TODO: nested "Ruby" => "case\nwhen (a == 1) then\n :a\nwhen (a == 2) then\n :b\nelse\n :c\nend", "ParseTree" => [:case, nil, [:when, [:array, [:call, [:vcall, :a], :==, [:array, [:lit, 1]]]], [:lit, :a]], [:when, [:array, [:call, [:vcall, :a], :==, [:array, [:lit, 2]]]], [:lit, :b]], [:lit, :c]], }, "case_splat" => { "Ruby" => "case a\nwhen :b, *c then\n d\nelse\n e\nend", "ParseTree" => [:case, [:vcall, :a], [:when, [:array, [:lit, :b], [:when, [:vcall, :c], nil]], # wtf? [:vcall, :d]], [:vcall, :e]], }, "cdecl" => { "Ruby" => "X = 42", "ParseTree" => [:cdecl, :X, [:lit, 42]], }, "class_plain" => { "Ruby" => "class X\n puts((1 + 1))\n def blah\n puts(\"hello\")\n end\nend", "ParseTree" => [:class, :X, nil, [:scope, [:block, [:fcall, :puts, [:array, [:call, [:lit, 1], :+, [:array, [:lit, 1]]]]], [:defn, :blah, [:scope, [:block, [:args], [:fcall, :puts, [:array, [:str, "hello"]]]]]]]]], }, "class_super_array" => { "Ruby" => "class X < Array\nend", "ParseTree" => [:class, :X, [:const, :Array], [:scope]], }, "class_super_expr" => { "Ruby" => "class X < expr\nend", "ParseTree" => [:class, :X, [:vcall, :expr], [:scope]], }, "class_super_object" => { "Ruby" => "class X < Object\nend", "ParseTree" => [:class, :X, [:const, :Object], [:scope]], }, "colon2" => { "Ruby" => "X::Y", "ParseTree" => [:colon2, [:const, :X], :Y], }, "colon3" => { "Ruby" => "::X", "ParseTree" => [:colon3, :X], }, "conditional1" => { # TODO: rename "Ruby" => "return 1 if (42 == 0)", "ParseTree" => [:if, [:call, [:lit, 42], :==, [:array, [:lit, 0]]], [:return, [:lit, 1]], nil], }, "conditional2" => { # TODO: remove "Ruby" => "return 2 unless (42 == 0)", "ParseTree" => [:if, [:call, [:lit, 42], :==, [:array, [:lit, 0]]], nil, [:return, [:lit, 2]]], }, "conditional3" => { "Ruby" => "if (42 == 0) then\n return 3\nelse\n return 4\nend", "ParseTree" => [:if, [:call, [:lit, 42], :==, [:array, [:lit, 0]]], [:return, [:lit, 3]], [:return, [:lit, 4]]], }, "conditional4" => { "Ruby" => "if (42 == 0) then\n return 2\nelsif (42 < 0) then\n return 3\nelse\n return 4\nend", "ParseTree" => [:if, [:call, [:lit, 42], :==, [:array, [:lit, 0]]], [:return, [:lit, 2]], [:if, [:call, [:lit, 42], :<, [:array, [:lit, 0]]], [:return, [:lit, 3]], [:return, [:lit, 4]]]], "Ruby2Ruby" => "if (42 == 0) then\n return 2\nelse\n if (42 < 0) then\n return 3\n else\n return 4\n end\nend", }, "conditional5" => { "Ruby" => "return if false unless true", "ParseTree" => [:if, [:true], nil, [:if, [:false], [:return], nil]], }, "conditional_post_if" => { "Ruby" => "a if b", "ParseTree" => [:if, [:vcall, :b], [:vcall, :a], nil], }, "conditional_post_if_not" => { "Ruby" => "a if not b", "ParseTree" => [:if, [:vcall, :b], nil, [:vcall, :a]], "Ruby2Ruby" => "a unless b" }, "conditional_post_unless" => { "Ruby" => "a unless b", "ParseTree" => [:if, [:vcall, :b], nil, [:vcall, :a]], }, "conditional_post_unless_not" => { "Ruby" => "a unless not b", "ParseTree" => [:if, [:vcall, :b], [:vcall, :a], nil], "Ruby2Ruby" => "a if b" }, "conditional_pre_if" => { "Ruby" => "if b then a end", "ParseTree" => [:if, [:vcall, :b], [:vcall, :a], nil], "Ruby2Ruby" => "a if b" }, "conditional_pre_if_not" => { "Ruby" => "if not b then a end", "ParseTree" => [:if, [:vcall, :b], nil, [:vcall, :a]], "Ruby2Ruby" => "a unless b" }, "conditional_pre_unless" => { "Ruby" => "unless b then a end", "ParseTree" => [:if, [:vcall, :b], nil, [:vcall, :a]], "Ruby2Ruby" => "a unless b" }, "conditional_pre_unless_not" => { "Ruby" => "unless not b then a end", "ParseTree" => [:if, [:vcall, :b], [:vcall, :a], nil], "Ruby2Ruby" => "a if b" }, "const" => { "Ruby" => "X", "ParseTree" => [:const, :X], }, "cvar" => { "Ruby" => "@@x", "ParseTree" => [:cvar, :@@x], }, "cvasgn" => { "Ruby" => "def x\n @@blah = 1\nend", "ParseTree" => [:defn, :x, [:scope, [:block, [:args], [:cvasgn, :@@blah, [:lit, 1]]]]] }, "cvasgn_cls_method" => { "Ruby" => "def self.quiet_mode=(boolean)\n @@quiet_mode = boolean\nend", "ParseTree" => [:defs, [:self], :quiet_mode=, [:scope, [:block, [:args, :boolean], [:cvasgn, :@@quiet_mode, [:lvar, :boolean]]]]], }, "cvdecl" => { "Ruby" => "class X\n @@blah = 1\nend", "ParseTree" => [:class, :X, nil, [:scope, [:cvdecl, :@@blah, [:lit, 1]]]], }, "dasgn_0" => { "Ruby" => "a.each { |x| b.each { |y| x = (x + 1) } if true }", "ParseTree" => [:iter, [:call, [:vcall, :a], :each], [:dasgn_curr, :x], [:if, [:true], [:iter, [:call, [:vcall, :b], :each], [:dasgn_curr, :y], [:dasgn, :x, [:call, [:dvar, :x], :+, [:array, [:lit, 1]]]]], nil]], }, "dasgn_1" => { # without mystery block / dasgn_curr "Ruby" => "a.each { |x| b.each { |y| c = (c + 1) } if true }", "ParseTree" => [:iter, [:call, [:vcall, :a], :each], [:dasgn_curr, :x], [:if, [:true], [:iter, [:call, [:vcall, :b], :each], [:dasgn_curr, :y], [:dasgn_curr, :c, [:call, [:dvar, :c], :+, [:array, [:lit, 1]]]]], nil]], }, "dasgn_2" => { # WITH mystery block / dasgn_curr "Ruby" => "a.each do |x|\n if true then\n c = 0\n b.each { |y| c = (c + 1) }\n \n end\nend", # FIX: hate that extra newline! "ParseTree" => [:iter, [:call, [:vcall, :a], :each], [:dasgn_curr, :x], [:block, [:dasgn_curr, :c], [:if, [:true], [:block, [:dasgn_curr, :c, [:lit, 0]], [:iter, [:call, [:vcall, :b], :each], [:dasgn_curr, :y], [:dasgn, :c, [:call, [:dvar, :c], :+, [:array, [:lit, 1]]]]]], nil]]], }, "dasgn_icky" => { # WITH mystery block / dasgn_curr "Ruby" => "a do\n v = nil\n assert_block(full_message) do\n begin\n yield\n rescue Exception => v\n break\n end\n end\nend", "ParseTree" => [:iter, [:fcall, :a], nil, [:block, [:dasgn_curr, :v], [:dasgn_curr, :v, [:nil]], [:iter, [:fcall, :assert_block, [:array, [:vcall, :full_message]]], nil, [:begin, [:rescue, [:yield], [:resbody, [:array, [:const, :Exception]], [:block, [:dasgn, :v, [:gvar, :$!]], [:break]]]]]]]], }, "dasgn_curr" => { "Ruby" => "data.each do |x, y|\n a = 1\n b = a\n b = a = x\nend", "ParseTree" => [:iter, [:call, [:vcall, :data], :each], [:masgn, [:array, [:dasgn_curr, :x], [:dasgn_curr, :y]]], [:block, [:dasgn_curr, :a, [:lit, 1]], [:dasgn_curr, :b, [:dvar, :a]], [:dasgn_curr, :b, [:dasgn_curr, :a, [:dvar, :x]]]]], }, "dasgn_mixed" => { "Ruby" => "t = 0\nns.each { |n| t += n }\n", "ParseTree" => [:block, [:lasgn, :t, [:lit, 0]], [:iter, [:call, [:vcall, :ns], :each], [:dasgn_curr, :n], [:lasgn, :t, [:call, [:lvar, :t], :+, [:array, [:dvar, :n]]]]]], "Ruby2Ruby" => "t = 0\nns.each { |n| t = (t + n) }\n", }, "defined" => { "Ruby" => "defined? $x", "ParseTree" => [:defined, [:gvar, :$x]], }, "defn_args_mand_opt_block" => { "Ruby" => "def x(a, b = 42, &d)\n p(a, b, d)\nend", "ParseTree" => [:defn, :x, [:scope, [:block, [:args, :a, :b, [:block, [:lasgn, :b, [:lit, 42]]]], [:block_arg, :d], [:fcall, :p, [:array, [:lvar, :a], [:lvar, :b], [:lvar, :d]]]]]] }, "defn_args_mand_opt_splat" => { "Ruby" => "def x(a, b = 42, *c)\n p(a, b, c)\nend", "ParseTree" => [:defn, :x, [:scope, [:block, [:args, :a, :b, :"*c", [:block, [:lasgn, :b, [:lit, 42]]]], [:fcall, :p, [:array, [:lvar, :a], [:lvar, :b], [:lvar, :c]]]]]] }, "defn_args_mand_opt_splat_block" => { "Ruby" => "def x(a, b = 42, \*c, &d)\n p(a, b, c, d)\nend", "ParseTree" => [:defn, :x, [:scope, [:block, [:args, :a, :b, "*c".intern, # s->e [:block, [:lasgn, :b, [:lit, 42]]]], [:block_arg, :d], [:fcall, :p, [:array, [:lvar, :a], [:lvar, :b], [:lvar, :c], [:lvar, :d]]]]]] }, "defn_args_mand_opt_splat_no_name" => { "Ruby" => "def x(a, b = 42, *)\n p(a, b)\nend", "ParseTree" => [:defn, :x, [:scope, [:block, [:args, :a, :b, :"*", [:block, [:lasgn, :b, [:lit, 42]]]], [:fcall, :p, [:array, [:lvar, :a], [:lvar, :b]]]]]] }, "defn_args_opt_block" => { "Ruby" => "def x(b = 42, &d)\n p(b, d)\nend", "ParseTree" => [:defn, :x, [:scope, [:block, [:args, :b, [:block, [:lasgn, :b, [:lit, 42]]]], [:block_arg, :d], [:fcall, :p, [:array, [:lvar, :b], [:lvar, :d]]]]]] }, "defn_args_opt_splat_no_name" => { "Ruby" => "def x(b = 42, *)\n p(b)\nend", "ParseTree" => [:defn, :x, [:scope, [:block, [:args, :b, :"*", [:block, [:lasgn, :b, [:lit, 42]]]], [:fcall, :p, [:array, [:lvar, :b]]]]]] }, "defn_empty" => { "Ruby" => "def empty\n # do nothing\nend", "ParseTree" => [:defn, :empty, [:scope, [:block, [:args], [:nil]]]], }, "defn_empty_args" => { "Ruby" => "def empty(*)\n # do nothing\nend", "ParseTree" => [:defn, :empty, [:scope, [:block, [:args, :*], [:nil]]]], }, "defn_lvar_boundary" => { # FIX: add do nothing comment to block "Ruby" => "mes = 42\ndef instantiate_all\n Thread.new do\n begin\n rescue RuntimeError => mes\n puts(mes)\n end\n end\nend\n", "ParseTree" => [:block, [:lasgn, :mes, [:lit, 42]], [:defn, :instantiate_all, [:scope, [:block, [:args], [:iter, [:call, [:const, :Thread], :new], nil, [:begin, [:rescue, [:resbody, [:array, [:const, :RuntimeError]], [:block, [:dasgn_curr, :mes, [:gvar, :$!]], [:fcall, :puts, [:array, [:dvar, :mes]]]]]]]]]]]], }, "defn_optargs" => { "Ruby" => "def x(a, *args)\n p(a, args)\nend", "ParseTree" => [:defn, :x, [:scope, [:block, [:args, :a, "*args".intern], [:fcall, :p, [:array, [:lvar, :a], [:lvar, :args]]]]]], }, "defn_or" => { "Ruby" => "def |(o)\n # do nothing\nend", "ParseTree" => [:defn, :|, [:scope, [:block, [:args, :o], [:nil]]]], }, "defn_rescue" => { "Ruby" => "def eql?(resource)\n (self.uuid == resource.uuid)\nrescue\n false\nend", "ParseTree" => [:defn, :eql?, [:scope, [:block, [:args, :resource], [:rescue, [:call, [:call, [:self], :uuid], :==, [:array, [:call, [:lvar, :resource], :uuid]]], [:resbody, nil, [:false]]]]]], "Ruby2Ruby" => "def eql?(resource)\n (self.uuid == resource.uuid) rescue false\nend", }, "defn_something_eh" => { "Ruby" => "def something?\n # do nothing\nend", "ParseTree" => [:defn, :something?, [:scope, [:block, [:args], [:nil]]]], }, "defn_splat_no_name" => { "Ruby" => "def x(a, *)\n p(a)\nend", "ParseTree" => [:defn, :x, [:scope, [:block, [:args, :a, "*".intern], [:fcall, :p, [:array, [:lvar, :a]]]]]], }, "defn_zarray" => { # tests memory allocation for returns "Ruby" => "def zarray\n a = []\n return a\nend", "ParseTree" => [:defn, :zarray, [:scope, [:block, [:args], [:lasgn, :a, [:zarray]], [:return, [:lvar, :a]]]]], }, "defs" => { "Ruby" => "def self.x(y)\n (y + 1)\nend", "ParseTree" => [:defs, [:self], :x, [:scope, [:block, [:args, :y], [:call, [:lvar, :y], :+, [:array, [:lit, 1]]]]]], }, "defs_args_mand_opt_splat_block" => { "Ruby" => "def self.x(a, b = 42, \*c, &d)\n (a + b)\nend", "ParseTree" => [:defs, [:self], :x, [:scope, [:block, [:args, :a, :b, :"*c", [:block, [:lasgn, :b, [:lit, 42]]]], [:block_arg, :d], [:call, [:lvar, :a], :+, [:array, [:lvar, :b]]]]]], }, "defs_empty" => { "Ruby" => "def self.empty\n # do nothing\nend", "ParseTree" => [:defs, [:self], :empty, [:scope, [:args]]], }, "defs_empty_args" => { "Ruby" => "def self.empty(*)\n # do nothing\nend", "ParseTree" => [:defs, [:self], :empty, [:scope, [:args, :*]]], }, "dmethod" => { "Ruby" => [Examples, :dmethod_added], "ParseTree" => [:defn, :dmethod_added, [:dmethod, :a_method, [:scope, [:block, [:args, :x], [:call, [:lvar, :x], :+, [:array, [:lit, 1]]]]]]], "Ruby2Ruby" => "def dmethod_added(x)\n (x + 1)\nend" }, "dot2" => { "Ruby" => "(a..b)", "ParseTree" => [:dot2, [:vcall, :a], [:vcall, :b]], }, "dot3" => { "Ruby" => "(a...b)", "ParseTree" => [:dot3, [:vcall, :a], [:vcall, :b]], }, "dregx" => { "Ruby" => "/x#\{(1 + 1)}y/", "ParseTree" => [:dregx, "x", [:evstr, [:call, [:lit, 1], :+, [:array, [:lit, 1]]]], [:str, "y"]], }, "dregx_interp" => { "Ruby" => "/#\{@rakefile}/", "ParseTree" => [:dregx, '', [:evstr, [:ivar, :@rakefile]]], }, "dregx_n" => { "Ruby" => '/#{1}/n', "ParseTree" => [:dregx, '', [:evstr, [:lit, 1]], 16], # TODO: use consts "Ruby2Ruby" => "/#\{1}/", # HACK - need to support regexp flags }, "dregx_once" => { "Ruby" => "/x#\{(1 + 1)}y/o", "ParseTree" => [:dregx_once, "x", [:evstr, [:call, [:lit, 1], :+, [:array, [:lit, 1]]]], [:str, "y"]], }, "dregx_once_n_interp" => { "Ruby" => "/#\{IAC}#\{SB}/no", "ParseTree" => [:dregx_once, '', [:evstr, [:const, :IAC]], [:evstr, [:const, :SB]], 16], "Ruby2Ruby" => "/#\{IAC}#\{SB}/o", # HACK }, "dstr" => { "Ruby" => "argl = 1\n\"x#\{argl}y\"\n", "ParseTree" => [:block, [:lasgn, :argl, [:lit, 1]], [:dstr, "x", [:evstr, [:lvar, :argl]], [:str, "y"]]], }, "dstr_2" => { "Ruby" => "argl = 1\n\"x#\{(\"%.2f\" % 3.14159)}y\"\n", "ParseTree" => [:block, [:lasgn, :argl, [:lit, 1]], [:dstr, "x", [:evstr, [:call, [:str, "%.2f"], :%, [:array, [:lit, 3.14159]]]], [:str, "y"]]], }, "dstr_3" => { "Ruby" => "max = 2\nargl = 1\n\"x#\{(\"%.#\{max}f\" % 3.14159)}y\"\n", "ParseTree" => [:block, [:lasgn, :max, [:lit, 2]], [:lasgn, :argl, [:lit, 1]], [:dstr, "x", [:evstr, [:call, [:dstr, "%.", [:evstr, [:lvar, :max]], [:str, "f"]], :%, [:array, [:lit, 3.14159]]]], [:str, "y"]]], }, "dstr_concat" => { "Ruby" => '"#{22}aa" "cd#{44}" "55" "#{66}"', "ParseTree" => [:dstr, "", [:evstr, [:lit, 22]], [:str, "aa"], [:str, "cd"], [:evstr, [:lit, 44]], [:str, "55"], [:evstr, [:lit, 66]]], "Ruby2Ruby" => '"#{22}aacd#{44}55#{66}"', }, "dstr_heredoc_yet_again" => { "Ruby" => "<<-EOF\ns1 '#\{RUBY_PLATFORM}' s2\n#\{__FILE__}\n EOF\n", "ParseTree" => [:dstr, "s1 '", [:evstr, [:const, :RUBY_PLATFORM]], [:str, "' s2\n"], [:str, "(string)"], [:str, "\n"]], "Ruby2Ruby" => "\"s1 '#\{RUBY_PLATFORM}' s2\\n(string)\\n\"" }, "dstr_nest" => { "Ruby" => "%Q[before [#\{nest}] after]", "ParseTree" => [:dstr, "before [", [:evstr, [:vcall, :nest]], [:str, "] after"]], "Ruby2Ruby" => "\"before [#\{nest}] after\"", }, "dstr_str_lit_start" => { "Ruby" => '"#{"blah"}#{__FILE__}:#{__LINE__}: warning: #{$!.message} (#{$!.class})"', "ParseTree" => [:dstr, "blah(string):", [:evstr, [:lit, 1]], [:str, ": warning: "], [:evstr, [:call, [:gvar, :$!], :message]], [:str, " ("], [:evstr, [:call, [:gvar, :$!], :class]], [:str, ")"]], "Ruby2Ruby" => '"blah(string):#{1}: warning: #{$!.message} (#{$!.class})"', }, "dstr_the_revenge" => { "Ruby" => '"before #{from} middle #{to} (#{__FILE__}:#{__LINE__})"', "ParseTree" => [:dstr, "before ", [:evstr, [:vcall, :from]], [:str, " middle "], [:evstr, [:vcall, :to]], [:str, " ("], [:str, "(string)"], [:str, ":"], [:evstr, [:lit, 1]], [:str, ")"]], "Ruby2Ruby" => '"before #{from} middle #{to} ((string):#{1})"', }, "dsym" => { "Ruby" => ":\"x#\{(1 + 1)}y\"", "ParseTree" => [:dsym, "x", [:evstr, [:call, [:lit, 1], :+, [:array, [:lit, 1]]]], [:str, "y"]], }, "dxstr" => { "Ruby" => "t = 5\n`touch #\{t}`\n", "ParseTree" => [:block, [:lasgn, :t, [:lit, 5]], [:dxstr, 'touch ', [:evstr, [:lvar, :t]]]], }, "ensure" => { "Ruby" => "begin\n (1 + 1)\nrescue SyntaxError => e1\n 2\nrescue Exception => e2\n 3\nelse\n 4\nensure\n 5 end", "ParseTree" => [:begin, [:ensure, [:rescue, [:call, [:lit, 1], :+, [:array, [:lit, 1]]], [:resbody, [:array, [:const, :SyntaxError]], [:block, [:lasgn, :e1, [:gvar, :$!]], [:lit, 2]], [:resbody, [:array, [:const, :Exception]], [:block, [:lasgn, :e2, [:gvar, :$!]], [:lit, 3]]]], [:lit, 4]], [:lit, 5]]], }, "false" => { "Ruby" => "false", "ParseTree" => [:false], }, "fbody" => { "Ruby" => [Examples, :an_alias], "ParseTree" => [:defn, :an_alias, [:fbody, [:scope, [:block, [:args, :x], [:call, [:lvar, :x], :+, [:array, [:lit, 1]]]]]]], "Ruby2Ruby" => "def an_alias(x)\n (x + 1)\nend" }, "fcall_arglist" => { "Ruby" => "m(42)", "ParseTree" => [:fcall, :m, [:array, [:lit, 42]]], }, "fcall_arglist_hash" => { "Ruby" => "m(:a => 1, :b => 2)", "ParseTree" => [:fcall, :m, [:array, [:hash, [:lit, :a], [:lit, 1], [:lit, :b], [:lit, 2]]]], }, "fcall_arglist_norm_hash" => { "Ruby" => "m(42, :a => 1, :b => 2)", "ParseTree" => [:fcall, :m, [:array, [:lit, 42], [:hash, [:lit, :a], [:lit, 1], [:lit, :b], [:lit, 2]]]], }, "fcall_arglist_norm_hash_splat" => { "Ruby" => "m(42, :a => 1, :b => 2, *c)", "ParseTree" => [:fcall, :m, [:argscat, [:array, [:lit, 42], [:hash, [:lit, :a], [:lit, 1], [:lit, :b], [:lit, 2]]], [:vcall, :c]]], }, "fcall_block" => { "Ruby" => "a(:b) { :c }", "ParseTree" => [:iter, [:fcall, :a, [:array, [:lit, :b]]], nil, [:lit, :c]], }, "fcall_keyword" => { "Ruby" => "42 if block_given?", "ParseTree" => [:if, [:fcall, :block_given?], [:lit, 42], nil], }, "flip2" => { "Ruby" => "x = if ((i % 4) == 0)..((i % 3) == 0) then\n i\nelse\n nil\nend", "ParseTree" => [:lasgn, :x, [:if, [:flip2, [:call, [:call, [:vcall, :i], :%, [:array, [:lit, 4]]], :==, [:array, [:lit, 0]]], [:call, [:call, [:vcall, :i], :%, [:array, [:lit, 3]]], :==, [:array, [:lit, 0]]]], [:vcall, :i], [:nil]]], }, "flip2_method" => { "Ruby" => "if 1..2.a?(b) then nil end", "ParseTree" => [:if, [:flip2, [:lit, 1], [:call, [:lit, 2], :a?, [:array, [:vcall, :b]]]], [:nil], nil], }, "flip3" => { "Ruby" => "x = if ((i % 4) == 0)...((i % 3) == 0) then\n i\nelse\n nil\nend", "ParseTree" => [:lasgn, :x, [:if, [:flip3, [:call, [:call, [:vcall, :i], :%, [:array, [:lit, 4]]], :==, [:array, [:lit, 0]]], [:call, [:call, [:vcall, :i], :%, [:array, [:lit, 3]]], :==, [:array, [:lit, 0]]]], [:vcall, :i], [:nil]]], }, "for" => { "Ruby" => "for o in ary do\n puts(o)\nend", "ParseTree" => [:for, [:vcall, :ary], [:lasgn, :o], [:fcall, :puts, [:array, [:lvar, :o]]]], }, "for_no_body" => { "Ruby" => "for i in (0..max) do\n # do nothing\nend", "ParseTree" => [:for, [:dot2, [:lit, 0], [:vcall, :max]], [:lasgn, :i]], }, "gasgn" => { "Ruby" => "$x = 42", "ParseTree" => [:gasgn, :$x, [:lit, 42]], }, "global" => { "Ruby" => "$stderr", "ParseTree" => [:gvar, :$stderr], }, "gvar" => { "Ruby" => "$x", "ParseTree" => [:gvar, :$x], }, "gvar_underscore" => { "Ruby" => "$_", "ParseTree" => [:gvar, :$_], }, "gvar_underscore_blah" => { "Ruby" => "$__blah", "ParseTree" => [:gvar, :$__blah], }, "hash" => { "Ruby" => "{ 1 => 2, 3 => 4 }", "ParseTree" => [:hash, [:lit, 1], [:lit, 2], [:lit, 3], [:lit, 4]], }, "hash_rescue" => { "Ruby" => "{ 1 => (2 rescue 3) }", "ParseTree" => [:hash, [:lit, 1], [:rescue, [:lit, 2], [:resbody, nil, [:lit, 3]]]], }, "iasgn" => { "Ruby" => "@a = 4", "ParseTree" => [:iasgn, :@a, [:lit, 4]], }, "if_block_condition" => { "Ruby" => "if (x = 5\n(x + 1)) then\n nil\nend", "ParseTree" => [:if, [:block, [:lasgn, :x, [:lit, 5]], [:call, [:lvar, :x], :+, [:array, [:lit, 1]]]], [:nil], nil], }, "if_lasgn_short" => { "Ruby" => "if x = obj.x then\n x.do_it\nend", "ParseTree" => [:if, [:lasgn, :x, [:call, [:vcall, :obj], :x]], [:call, [:lvar, :x], :do_it], nil], }, "iteration1" => { "Ruby" => "loop { }", "ParseTree" => [:iter, [:fcall, :loop], nil], }, "iteration2" => { "Ruby" => "array = [1, 2, 3]\narray.each { |x| puts(x.to_s) }\n", "ParseTree" => [:block, [:lasgn, :array, [:array, [:lit, 1], [:lit, 2], [:lit, 3]]], [:iter, [:call, [:lvar, :array], :each], [:dasgn_curr, :x], [:fcall, :puts, [:array, [:call, [:dvar, :x], :to_s]]]]], }, "iteration3" => { "Ruby" => "1.upto(3) { |n| puts(n.to_s) }", "ParseTree" => [:iter, [:call, [:lit, 1], :upto, [:array, [:lit, 3]]], [:dasgn_curr, :n], [:fcall, :puts, [:array, [:call, [:dvar, :n], :to_s]]]], }, "iteration4" => { "Ruby" => "3.downto(1) { |n| puts(n.to_s) }", "ParseTree" => [:iter, [:call, [:lit, 3], :downto, [:array, [:lit, 1]]], [:dasgn_curr, :n], [:fcall, :puts, [:array, [:call, [:dvar, :n], :to_s]]]], }, "iteration5" => { "Ruby" => "argl = 10\nwhile (argl >= 1) do\n puts(\"hello\")\n argl = (argl - 1)\nend\n", "ParseTree" => [:block, [:lasgn, :argl, [:lit, 10]], [:while, [:call, [:lvar, :argl], ">=".intern, [:array, [:lit, 1]]], [:block, [:fcall, :puts, [:array, [:str, "hello"]]], [:lasgn, :argl, [:call, [:lvar, :argl], "-".intern, [:array, [:lit, 1]]]]], true]], }, "iteration6" => { "Ruby" => "array1 = [1, 2, 3]\narray2 = [4, 5, 6, 7]\narray1.each do |x|\n array2.each do |y|\n puts(x.to_s)\n puts(y.to_s)\n end\nend\n", "ParseTree" => [:block, [:lasgn, :array1, [:array, [:lit, 1], [:lit, 2], [:lit, 3]]], [:lasgn, :array2, [:array, [:lit, 4], [:lit, 5], [:lit, 6], [:lit, 7]]], [:iter, [:call, [:lvar, :array1], :each], [:dasgn_curr, :x], [:iter, [:call, [:lvar, :array2], :each], [:dasgn_curr, :y], [:block, [:fcall, :puts, [:array, [:call, [:dvar, :x], :to_s]]], [:fcall, :puts, [:array, [:call, [:dvar, :y], :to_s]]]]]]], }, "iteration7" => { "Ruby" => "a { |b, c| p(c) }", "ParseTree" => [:iter, [:fcall, :a], [:masgn, [:array, [:dasgn_curr, :b], [:dasgn_curr, :c]]], [:fcall, :p, [:array, [:dvar, :c]]]], }, "iteration8" => { "Ruby" => "a { |b, c, *d| p(c) }", "ParseTree" => [:iter, [:fcall, :a], [:masgn, [:array, [:dasgn_curr, :b], [:dasgn_curr, :c]], [:dasgn_curr, :d]], [:fcall, :p, [:array, [:dvar, :c]]]], }, "iteration9" => { "Ruby" => "a { |b, c, *| p(c) }", "ParseTree" => [:iter, [:fcall, :a], [:masgn, [:array, [:dasgn_curr, :b], [:dasgn_curr, :c]], [:splat]], [:fcall, :p, [:array, [:dvar, :c]]]], }, "iteration9" => { "Ruby" => "a { |*| p(c) }", "ParseTree" => [:iter, [:fcall, :a], [:masgn, [:splat]], [:fcall, :p, [:array, [:vcall, :c]]]], }, "iteration_dasgn_curr_dasgn_madness" => { "Ruby" => "as.each { |a|\n b += a.b(false) }", "ParseTree" => [:iter, [:call, [:vcall, :as], :each], [:dasgn_curr, :a], [:dasgn_curr, :b, [:call, [:dvar, :b], :+, [:array, [:call, [:dvar, :a], :b, [:array, [:false]]]]]]], "Ruby2Ruby" => "as.each { |a| b = (b + a.b(false)) }", }, "iteration_double_var" => { "Ruby" => "a do |x|\n b do |x| \n puts x\n end\nend", "ParseTree" => [:iter, [:fcall, :a], [:dasgn_curr, :x], [:iter, [:fcall, :b], [:dasgn, :x], [:fcall, :puts, [:array, [:dvar, :x]]]]], "Ruby2Ruby" => "a { |x| b { |x| puts(x) } }", }, "iteration_masgn" => { "Ruby" => "define_method(method) { |*args| }", "ParseTree" => [:iter, [:fcall, :define_method, [:array, [:vcall, :method]]], [:masgn, [:dasgn_curr, :args]]], }, "ivar" => { "Ruby" => [Examples, :reader], "ParseTree" => [:defn, :reader, [:ivar, :@reader]], "Ruby2Ruby" => "attr_reader :reader" }, "lasgn_array" => { "Ruby" => "var = [\"foo\", \"bar\"]", "ParseTree" => [:lasgn, :var, [:array, [:str, "foo"], [:str, "bar"]]], }, "lasgn_call" => { "Ruby" => "c = (2 + 3)", "ParseTree" => [:lasgn, :c, [:call, [:lit, 2], :+, [:array, [:lit, 3]]]], }, "lit_bool_false" => { "Ruby" => "false", "ParseTree" => [:false], }, "lit_bool_true" => { "Ruby" => "true", "ParseTree" => [:true], }, "lit_float" => { "Ruby" => "1.1", "ParseTree" => [:lit, 1.1], }, "lit_long" => { "Ruby" => "1", "ParseTree" => [:lit, 1], }, "lit_long_negative" => { "Ruby" => "-1", "ParseTree" => [:lit, -1], }, "lit_range2" => { "Ruby" => "(1..10)", "ParseTree" => [:lit, 1..10], }, "lit_range3" => { "Ruby" => "(1...10)", "ParseTree" => [:lit, 1...10], }, "lit_regexp" => { "Ruby" => "/x/", "ParseTree" => [:lit, /x/], }, "lit_regexp_i_wwtt" => { "Ruby" => 'str.split(//i)', "ParseTree" => [:call, [:vcall, :str], :split, [:array, [:lit, //i]]], }, "lit_regexp_n" => { "Ruby" => "/x/n", "ParseTree" => [:lit, /x/n], }, "lit_regexp_once" => { "Ruby" => "/x/o", "ParseTree" => [:lit, /x/], "Ruby2Ruby" => "/x/", }, "lit_sym" => { "Ruby" => ":x", "ParseTree" => [:lit, :x], }, "lit_sym_splat" => { "Ruby" => ":\"*args\"", "ParseTree" => [:lit, :"*args"], }, "lvar_def_boundary" => { # HACK: put # do nothing back under begin "Ruby" => "b = 42\ndef a\n c do\n begin\n rescue RuntimeError => b\n puts(b)\n end\n end\nend\n", "ParseTree" => [:block, [:lasgn, :b, [:lit, 42]], [:defn, :a, [:scope, [:block, [:args], [:iter, [:fcall, :c], nil, [:begin, [:rescue, [:resbody, [:array, [:const, :RuntimeError]], [:block, [:dasgn_curr, :b, [:gvar, :$!]], [:fcall, :puts, [:array, [:dvar, :b]]]]]]]]]]]], }, "masgn" => { "Ruby" => "a, b = c, d", "ParseTree" => [:masgn, [:array, [:lasgn, :a], [:lasgn, :b]], [:array, [:vcall, :c], [:vcall, :d]]], }, "masgn_argscat" => { "Ruby" => "a, b, *c = 1, 2, *[3, 4]", "ParseTree" => [:masgn, [:array, [:lasgn, :a], [:lasgn, :b]], [:lasgn, :c], [:argscat, [:array, [:lit, 1], [:lit, 2]], [:array, [:lit, 3], [:lit, 4]]]], }, "masgn_attrasgn" => { "Ruby" => "a, b.c = d, e", "ParseTree" => [:masgn, [:array, [:lasgn, :a], [:attrasgn, [:vcall, :b], :c=]], [:array, [:vcall, :d], [:vcall, :e]]], }, "masgn_iasgn" => { "Ruby" => "a, @b = c, d", "ParseTree" => [:masgn, [:array, [:lasgn, :a], [:iasgn, "@b".intern]], [:array, [:vcall, :c], [:vcall, :d]]], }, "masgn_masgn" => { "Ruby" => "a, (b, c) = [1, [2, 3]]", "ParseTree" => [:masgn, [:array, [:lasgn, :a], [:masgn, [:array, [:lasgn, :b], [:lasgn, :c]]]], [:to_ary, [:array, [:lit, 1], [:array, [:lit, 2], [:lit, 3]]]]] }, "masgn_splat" => { "Ruby" => "a, b, *c = d, e, f, g", "ParseTree" => [:masgn, [:array, [:lasgn, :a], [:lasgn, :b]], [:lasgn, :c], [:array, [:vcall, :d], [:vcall, :e], [:vcall, :f], [:vcall, :g]]] }, "masgn_splat_no_name_to_ary" => { "Ruby" => "a, b, * = c", "ParseTree" => [:masgn, [:array, [:lasgn, :a], [:lasgn, :b]], [:splat], [:to_ary, [:vcall, :c]]], }, "masgn_splat_no_name_trailing" => { "Ruby" => "a, b, = c", "ParseTree" => [:masgn, [:array, [:lasgn, :a], [:lasgn, :b]], [:to_ary, [:vcall, :c]]], "Ruby2Ruby" => "a, b = c", # TODO: check this is right }, "masgn_splat_to_ary" => { "Ruby" => "a, b, *c = d", "ParseTree" => [:masgn, [:array, [:lasgn, :a], [:lasgn, :b]], [:lasgn, :c], [:to_ary, [:vcall, :d]]], }, "masgn_splat_to_ary2" => { "Ruby" => "a, b, *c = d.e(\"f\")", "ParseTree" => [:masgn, [:array, [:lasgn, :a], [:lasgn, :b]], [:lasgn, :c], [:to_ary, [:call, [:vcall, :d], :e, [:array, [:str, 'f']]]]], }, "match" => { "Ruby" => "1 if /x/", "ParseTree" => [:if, [:match, [:lit, /x/]], [:lit, 1], nil], }, "match2" => { "Ruby" => "/x/ =~ \"blah\"", "ParseTree" => [:match2, [:lit, /x/], [:str, "blah"]], }, "match3" => { "Ruby" => "\"blah\" =~ /x/", "ParseTree" => [:match3, [:lit, /x/], [:str, "blah"]], }, "module" => { "Ruby" => "module X\n def y\n # do nothing\n end\nend", "ParseTree" => [:module, :X, [:scope, [:defn, :y, [:scope, [:block, [:args], [:nil]]]]]], }, "next" => { "Ruby" => "loop { next if false }", "ParseTree" => [:iter, [:fcall, :loop], nil, [:if, [:false], [:next], nil]], }, "next_arg" => { "Ruby" => "loop { next 42 if false }", "ParseTree" => [:iter, [:fcall, :loop], nil, [:if, [:false], [:next, [:lit, 42]], nil]], }, "not" => { "Ruby" => "(not true)", "ParseTree" => [:not, [:true]], }, "nth_ref" => { "Ruby" => "$1", "ParseTree" => [:nth_ref, 1], }, "op_asgn1" => { "Ruby" => "b = []\nb[1] ||= 10\nb[2] &&= 11\nb[3] += 12\n", "ParseTree" => [:block, [:lasgn, :b, [:zarray]], [:op_asgn1, [:lvar, :b], [:array, [:lit, 1]], "||".intern, [:lit, 10]], # s->e [:op_asgn1, [:lvar, :b], [:array, [:lit, 2]], "&&".intern, [:lit, 11]], # s->e [:op_asgn1, [:lvar, :b], [:array, [:lit, 3]], :+, [:lit, 12]]], }, "op_asgn2" => { "Ruby" => "s = Struct.new(:var)\nc = s.new(nil)\nc.var ||= 20\nc.var &&= 21\nc.var += 22\nc.d.e.f ||= 42\n", "ParseTree" => [:block, [:lasgn, :s, [:call, [:const, :Struct], :new, [:array, [:lit, :var]]]], [:lasgn, :c, [:call, [:lvar, :s], :new, [:array, [:nil]]]], [:op_asgn2, [:lvar, :c], :var=, "||".intern, # s->e [:lit, 20]], [:op_asgn2, [:lvar, :c], :var=, "&&".intern, # s->e [:lit, 21]], [:op_asgn2, [:lvar, :c], :var=, :+, [:lit, 22]], [:op_asgn2, [:call, [:call, [:lvar, :c], :d], :e], :f=, "||".intern, [:lit, 42]]], }, "op_asgn2_self" => { "Ruby" => "self.Bag ||= Bag.new", "ParseTree" => [:op_asgn2, [:self], :"Bag=", :"||", [:call, [:const, :Bag], :new]], }, "op_asgn_and" => { "Ruby" => "a = 0\na &&= 2\n", "ParseTree" => [:block, [:lasgn, :a, [:lit, 0]], [:op_asgn_and, [:lvar, :a], [:lasgn, :a, [:lit, 2]]]], }, "op_asgn_and_ivar2" => { # eww... stupid rubygems "Ruby" => "@fetcher &&= new(Gem.configuration[:http_proxy])", "ParseTree" => [:op_asgn_and, [:ivar, :@fetcher], [:iasgn, :@fetcher, [:fcall, :new, [:array, [:call, [:call, [:const, :Gem], :configuration], :[], [:array, [:lit, :http_proxy]]]]]]], }, "op_asgn_or" => { "Ruby" => "a = 0\na ||= 1\n", "ParseTree" => [:block, [:lasgn, :a, [:lit, 0]], [:op_asgn_or, [:lvar, :a], [:lasgn, :a, [:lit, 1]]]], }, "op_asgn_or_block" => { "Ruby" => "a ||= begin\n b\n rescue\n c\n end", "ParseTree" => [:op_asgn_or, [:lvar, :a], [:lasgn, :a, [:rescue, [:vcall, :b], [:resbody, nil, [:vcall, :c]]]]], "Ruby2Ruby" => "a ||= b rescue c", }, "op_asgn_or_ivar" => { "Ruby" => "@v ||= { }", "ParseTree" => [:op_asgn_or, [:ivar, :@v], [:iasgn, :@v, [:hash]]], }, "op_asgn_or_ivar2" => { # eww... stupid rubygems "Ruby" => "@fetcher ||= new(Gem.configuration[:http_proxy])", "ParseTree" => [:op_asgn_or, [:ivar, :@fetcher], [:iasgn, :@fetcher, [:fcall, :new, [:array, [:call, [:call, [:const, :Gem], :configuration], :[], [:array, [:lit, :http_proxy]]]]]]], }, "or" => { "Ruby" => "(a or b)", "ParseTree" => [:or, [:vcall, :a], [:vcall, :b]], }, "or_big" => { "Ruby" => "((a or b) or (c and d))", "ParseTree" => [:or, [:or, [:vcall, :a], [:vcall, :b]], [:and, [:vcall, :c], [:vcall, :d]]], }, "or_big2" => { "Ruby" => "((a || b) || (c && d))", "ParseTree" => [:or, [:or, [:vcall, :a], [:vcall, :b]], [:and, [:vcall, :c], [:vcall, :d]]], "Ruby2Ruby" => "((a or b) or (c and d))", }, "postexe" => { "Ruby" => "END { 1 }", "ParseTree" => [:iter, [:postexe], nil, [:lit, 1]], }, "proc_args" => { "Ruby" => "proc { |x| (x + 1) }", "ParseTree" => [:iter, [:fcall, :proc], [:dasgn_curr, :x], [:call, [:dvar, :x], :+, [:array, [:lit, 1]]]], }, "proc_no_args" => { "Ruby" => "proc { (x + 1) }", "ParseTree" => [:iter, [:fcall, :proc], nil, [:call, [:vcall, :x], :+, [:array, [:lit, 1]]]], }, "proc_zero_args" => { "Ruby" => "proc { || (x + 1) }", "ParseTree" => [:iter, [:fcall, :proc], 0, [:call, [:vcall, :x], :+, [:array, [:lit, 1]]]], }, "redo" => { "Ruby" => "loop { redo if false }", "ParseTree" => [:iter, [:fcall, :loop], nil, [:if, [:false], [:redo], nil]], }, "rescue" => { "Ruby" => "blah rescue nil", "ParseTree" => [:rescue, [:vcall, :blah], [:resbody, nil, [:nil]]], }, "rescue_block_body" => { "Ruby" => "begin\n a\nrescue => e\n c\n d\nend", "ParseTree" => [:begin, [:rescue, [:vcall, :a], [:resbody, nil, [:block, [:lasgn, :e, [:gvar, :$!]], [:vcall, :c], [:vcall, :d]]]]], }, "rescue_block_nada" => { "Ruby" => "begin\n blah\nrescue\n # do nothing\nend", "ParseTree" => [:begin, [:rescue, [:vcall, :blah], [:resbody, nil]]] }, "rescue_exceptions" => { "Ruby" => "begin\n blah\nrescue RuntimeError => r\n # do nothing\nend", "ParseTree" => [:begin, [:rescue, [:vcall, :blah], [:resbody, [:array, [:const, :RuntimeError]], [:lasgn, :r, [:gvar, :$!]]]]], }, "retry" => { "Ruby" => "retry", "ParseTree" => [:retry], }, "return_0" => { "Ruby" => "return", "ParseTree" => [:return], }, "return_1" => { "Ruby" => "return 1", "ParseTree" => [:return, [:lit, 1]], }, "return_n" => { "Ruby" => "return 1, 2, 3", "ParseTree" => [:return, [:array, [:lit, 1], [:lit, 2], [:lit, 3]]], "Ruby2Ruby" => "return [1, 2, 3]", }, "sclass" => { "Ruby" => "class << self\n 42\nend", "ParseTree" => [:sclass, [:self], [:scope, [:lit, 42]]], }, "sclass_trailing_class" => { "Ruby" => "class A\n class << self\n a\n end\n class B\n end\nend", "ParseTree" => [:class, :A, nil, [:scope, [:block, [:sclass, [:self], [:scope, [:vcall, :a]]], [:class, :B, nil, [:scope]]]]], }, "splat" => { "Ruby" => "def x(*b)\n a(*b)\nend", "ParseTree" => [:defn, :x, [:scope, [:block, [:args, :"*b"], [:fcall, :a, [:splat, [:lvar, :b]]]]]], }, "str" => { "Ruby" => '"x"', "ParseTree" => [:str, "x"], }, "str_concat_newline" => { "Ruby" => '"before" \\ " after"', "ParseTree" => [:str, "before after"], "Ruby2Ruby" => '"before after"', }, "str_concat_space" => { "Ruby" => '"before" " after"', "ParseTree" => [:str, "before after"], "Ruby2Ruby" => '"before after"', }, "str_heredoc" => { "Ruby" => "<<'EOM'\n blah\nblah\nEOM\n", "ParseTree" => [:str, " blah\nblah\n"], "Ruby2Ruby" => "\" blah\\nblah\\n\"", }, "str_heredoc_call" => { "Ruby" => "<<'EOM'.strip\n blah\nblah\nEOM\n", "ParseTree" => [:call, [:str, " blah\nblah\n"], :strip], "Ruby2Ruby" => "\" blah\\nblah\\n\".strip", }, "str_heredoc_double" => { "Ruby" => "a += <<-BEGIN + b + <<-END\n first\nBEGIN\n second\nEND", "ParseTree" => [:lasgn, :a, [:call, [:lvar, :a], :+, [:array, [:call, [:call, [:str, " first\n"], :+, [:array, [:vcall, :b]]], :+, [:array, [:str, " second\n"]]]]]], "Ruby2Ruby" => "a = (a + ((\" first\\n\" + b) + \" second\\n\"))", }, "dstr_heredoc_expand" => { "Ruby" => "< [:dstr, " blah\n", [:evstr, [:call, [:lit, 1], :+, [:array, [:lit, 1]]]], [:str, "blah\n"]], "Ruby2Ruby" => "\" blah\\n#\{(1 + 1)}blah\\n\"", }, "str_heredoc_indent" => { "Ruby" => "<<-EOM\n blah\nblah\n\n EOM\n", "ParseTree" => [:str, " blah\nblah\n\n"], "Ruby2Ruby" => "\" blah\\nblah\\n\\n\"", }, "dstr_heredoc_windoze_sucks" => { "Ruby" => "<<-EOF\r\ndef test_#\{action}_valid_feed\r\n EOF\r\n", "ParseTree" => [:dstr, 'def test_', [:evstr, [:vcall, :action]], [:str, "_valid_feed\n"]], "Ruby2Ruby" => "\"def test_#\{action}_valid_feed\\n\"", }, "str_interp_file" => { "Ruby" => '"file = #{__FILE__} "', "ParseTree" => [:str, "file = (string)\n"], "Ruby2Ruby" => '"file = (string)\\n"', }, "structure_extra_block_for_dvar_scoping" => { "Ruby" => "a.b do |c, d|\n unless e.f(c) then\n g = false\n d.h { |x, i| g = true }\n \n end\nend", # FIX: don't like the extra return "ParseTree" => [:iter, [:call, [:vcall, :a], :b], [:masgn, [:array, [:dasgn_curr, :c], [:dasgn_curr, :d]]], [:block, [:dasgn_curr, :g], [:if, [:call, [:vcall, :e], :f, [:array, [:dvar, :c]]], nil, [:block, [:dasgn_curr, :g, [:false]], [:iter, [:call, [:dvar, :d], :h], [:masgn, [:array, [:dasgn_curr, :x], [:dasgn_curr, :i]]], [:dasgn, :g, [:true]]]]]]], }, "structure_remove_begin_1" => { "Ruby" => "a << begin\n b\n rescue\n c\n end", "ParseTree" => [:call, [:vcall, :a], :<<, [:array, [:rescue, [:vcall, :b], [:resbody, nil, [:vcall, :c]]]]], "Ruby2Ruby" => "(a << b rescue c)", }, "structure_remove_begin_2" => { "Ruby" => "a = if c\n begin\n b\n rescue\n nil\n end\n end\na", "ParseTree" => [:block, [:lasgn, :a, [:if, [:vcall, :c], [:rescue, [:vcall, :b], [:resbody, nil, [:nil]]], nil]], [:lvar, :a]], "Ruby2Ruby" => "a = b rescue nil if c\na\n", # OMG that's awesome }, "structure_unused_literal_wwtt" => { "Ruby" => "\"prevent the above from infecting rdoc\"\n\nmodule Graffle\nend", "ParseTree" => [:module, :Graffle, [:scope]], "Ruby2Ruby" => "module Graffle\nend", }, # TODO: all supers need to pass args "super" => { "Ruby" => "def x\n super(4)\nend", "ParseTree" => [:defn, :x, [:scope, [:block, [:args], [:super, [:array, [:lit, 4]]]]]], }, "super_block_pass" => { "Ruby" => "super(a, &b)", "ParseTree" => [:block_pass, [:vcall, :b], [:super, [:array, [:vcall, :a]]]], }, "super_block_splat" => { "Ruby" => "super(a, *b)", "ParseTree" => [:super, [:argscat, [:array, [:vcall, :a]], [:vcall, :b]]], }, "super_multi" => { "Ruby" => "def x\n super(4, 2, 1)\nend", "ParseTree" => [:defn, :x, [:scope, [:block, [:args], [:super, [:array, [:lit, 4], [:lit, 2], [:lit, 1]]]]]], }, "svalue" => { "Ruby" => "a = *b", "ParseTree" => [:lasgn, :a, [:svalue, [:splat, [:vcall, :b]]]], }, "to_ary" => { "Ruby" => "a, b = c", "ParseTree" => [:masgn, [:array, [:lasgn, :a], [:lasgn, :b]], [:to_ary, [:vcall, :c]]], }, "true" => { "Ruby" => "true", "ParseTree" => [:true], }, "undef" => { "Ruby" => "undef :x", "ParseTree" => [:undef, [:lit, :x]], }, "undef_2" => { "Ruby" => "undef :x, :y", "ParseTree" => [:block, [:undef, [:lit, :x]], [:undef, [:lit, :y]]], "Ruby2Ruby" => "undef :x\nundef :y\n", }, "undef_3" => { "Ruby" => "undef :x, :y, :z", "ParseTree" => [:block, [:undef, [:lit, :x]], [:undef, [:lit, :y]], [:undef, [:lit, :z]]], "Ruby2Ruby" => "undef :x\nundef :y\nundef :z\n", }, "undef_block_1" => { "Ruby" => "f1\nundef :x\n", # TODO: don't like the extra return "ParseTree" => [:block, [:vcall, :f1], [:undef, [:lit, :x]]], }, "undef_block_2" => { "Ruby" => "f1\nundef :x, :y", "ParseTree" => [:block, [:vcall, :f1], [:block, [:undef, [:lit, :x]], [:undef, [:lit, :y]], ]], "Ruby2Ruby" => "f1\n(undef :x\nundef :y)\n", }, "undef_block_3" => { "Ruby" => "f1\nundef :x, :y, :z", "ParseTree" => [:block, [:vcall, :f1], [:block, [:undef, [:lit, :x]], [:undef, [:lit, :y]], [:undef, [:lit, :z]], ]], "Ruby2Ruby" => "f1\n(undef :x\nundef :y\nundef :z)\n", }, "undef_block_3_post" => { "Ruby" => "undef :x, :y, :z\nf2", "ParseTree" => [:block, [:undef, [:lit, :x]], [:undef, [:lit, :y]], [:undef, [:lit, :z]], [:vcall, :f2]], "Ruby2Ruby" => "undef :x\nundef :y\nundef :z\nf2\n", }, "undef_block_wtf" => { "Ruby" => "f1\nundef :x, :y, :z\nf2", "ParseTree" => [:block, [:vcall, :f1], [:block, [:undef, [:lit, :x]], [:undef, [:lit, :y]], [:undef, [:lit, :z]]], [:vcall, :f2]], "Ruby2Ruby" => "f1\n(undef :x\nundef :y\nundef :z)\nf2\n", }, "until_post" => { "Ruby" => "begin\n (1 + 1)\nend until false", "ParseTree" => [:until, [:false], [:call, [:lit, 1], :+, [:array, [:lit, 1]]], false], }, "until_post_not" => { "Ruby" => "begin\n (1 + 1)\nend until not true", "ParseTree" => [:while, [:true], [:call, [:lit, 1], :+, [:array, [:lit, 1]]], false], "Ruby2Ruby" => "begin\n (1 + 1)\nend while true", }, "until_pre" => { "Ruby" => "until false do\n (1 + 1)\nend", "ParseTree" => [:until, [:false], [:call, [:lit, 1], :+, [:array, [:lit, 1]]], true], }, "until_pre_mod" => { "Ruby" => "(1 + 1) until false", "ParseTree" => [:until, [:false], [:call, [:lit, 1], :+, [:array, [:lit, 1]]], true], "Ruby2Ruby" => "until false do\n (1 + 1)\nend", }, "until_pre_not" => { "Ruby" => "until not true do\n (1 + 1)\nend", "ParseTree" => [:while, [:true], [:call, [:lit, 1], :+, [:array, [:lit, 1]]], true], "Ruby2Ruby" => "while true do\n (1 + 1)\nend", }, "until_pre_not_mod" => { "Ruby" => "(1 + 1) until not true", "ParseTree" => [:while, [:true], [:call, [:lit, 1], :+, [:array, [:lit, 1]]], true], "Ruby2Ruby" => "while true do\n (1 + 1)\nend", }, "valias" => { "Ruby" => "alias $y $x", "ParseTree" => [:valias, :$y, :$x], }, "vcall" => { "Ruby" => "method", "ParseTree" => [:vcall, :method], }, "while_post" => { "Ruby" => "begin\n (1 + 1)\nend while false", "ParseTree" => [:while, [:false], [:call, [:lit, 1], :+, [:array, [:lit, 1]]], false], }, "while_post_not" => { "Ruby" => "begin\n (1 + 1)\nend while not true", "ParseTree" => [:until, [:true], [:call, [:lit, 1], :+, [:array, [:lit, 1]]], false], "Ruby2Ruby" => "begin\n (1 + 1)\nend until true", }, "while_pre" => { "Ruby" => "while false do\n (1 + 1)\nend", "ParseTree" => [:while, [:false], [:call, [:lit, 1], :+, [:array, [:lit, 1]]], true], }, "while_pre_mod" => { "Ruby" => "(1 + 1) while false", "ParseTree" => [:while, [:false], [:call, [:lit, 1], :+, [:array, [:lit, 1]]], true], "Ruby2Ruby" => "while false do\n (1 + 1)\nend", # FIX can be one liner }, "while_pre_nil" => { "Ruby" => "while false do\nend", "ParseTree" => [:while, [:false], nil, true], }, "while_pre_not" => { "Ruby" => "while not true do\n (1 + 1)\nend", "ParseTree" => [:until, [:true], [:call, [:lit, 1], :+, [:array, [:lit, 1]]], true], "Ruby2Ruby" => "until true do\n (1 + 1)\nend", }, "while_pre_not_mod" => { "Ruby" => "(1 + 1) while not true", "ParseTree" => [:until, [:true], [:call, [:lit, 1], :+, [:array, [:lit, 1]]], true], "Ruby2Ruby" => "until true do\n (1 + 1)\nend", # FIX }, "xstr" => { "Ruby" => "`touch 5`", "ParseTree" => [:xstr, 'touch 5'], }, "yield" => { "Ruby" => "yield", "ParseTree" => [:yield], }, "yield_arg" => { "Ruby" => "yield(42)", "ParseTree" => [:yield, [:lit, 42]], }, "yield_args" => { "Ruby" => "yield(42, 24)", "ParseTree" => [:yield, [:array, [:lit, 42], [:lit, 24]]], }, "zarray" => { "Ruby" => "a = []", "ParseTree" => [:lasgn, :a, [:zarray]], }, "zsuper" => { "Ruby" => "def x\n super\nend", "ParseTree" => [:defn, :x, [:scope, [:block, [:args], [:zsuper]]]], }, } def self.previous(key, extra=0) idx = @@testcase_order.index(key)-1-extra case key when "RubyToRubyC" then idx -= 1 end @@testcase_order[idx] end def self.inherited(c) output_name = c.name.to_s.sub(/^Test/, '') raise "Unknown class #{c} in @@testcase_order" unless @@testcase_order.include? output_name input_name = self.previous(output_name) @@testcases.each do |node, data| next if [:skip, :unsupported].include? data[input_name] next if data[output_name] == :skip c.send(:define_method, "test_#{node}".intern) do flunk "Processor is nil" if processor.nil? assert data.has_key?(input_name), "Unknown input data" unless data.has_key?(output_name) then $stderr.puts "add_test(#{node.inspect}, :same)" end assert data.has_key?(output_name), "Missing test data: #{self.class} #{node}" input = data[input_name].deep_clone expected = if data[output_name] == :same then input else data[output_name] end.deep_clone case expected when :unsupported then assert_raises(UnsupportedNodeError) do processor.process(input) end else extra_expected = [] extra_input = [] _, expected, extra_expected = *expected if Array === expected and expected.first == :defx _, input, extra_input = *input if Array === input and input.first == :defx debug = input.deep_clone $-w = nil if node == "match" assert_equal expected, processor.process(input), "failed on input: #{debug.inspect}" $-w = true if node == "match" extra_input.each do |input| processor.process(input) end extra = processor.extra_methods rescue [] assert_equal extra_expected, extra end end end end undef_method :default_test rescue nil end