summaryrefslogtreecommitdiff
path: root/test/ruby/test_ast.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby/test_ast.rb')
-rw-r--r--test/ruby/test_ast.rb218
1 files changed, 215 insertions, 3 deletions
diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb
index 29da607fc5..940c4de9d7 100644
--- a/test/ruby/test_ast.rb
+++ b/test/ruby/test_ast.rb
@@ -2,6 +2,7 @@
require 'test/unit'
require 'tempfile'
require 'pp'
+require_relative '../lib/parser_support'
class RubyVM
module AbstractSyntaxTree
@@ -272,7 +273,7 @@ class TestAst < Test::Unit::TestCase
assert_parse("def m; defined?(retry); end")
assert_parse("!begin defined?(retry); end")
assert_parse("begin rescue; else; defined?(retry); end")
- assert_parse("begin rescue; ensure; defined?(retry); end")
+ assert_parse("begin rescue; ensure; p defined?(retry); end")
assert_parse("END {defined?(retry)}")
assert_parse("begin rescue; END {defined?(retry)}; end")
assert_parse("!defined? retry")
@@ -280,7 +281,7 @@ class TestAst < Test::Unit::TestCase
assert_parse("def m; defined? retry; end")
assert_parse("!begin defined? retry; end")
assert_parse("begin rescue; else; defined? retry; end")
- assert_parse("begin rescue; ensure; defined? retry; end")
+ assert_parse("begin rescue; ensure; p defined? retry; end")
assert_parse("END {defined? retry}")
assert_parse("begin rescue; END {defined? retry}; end")
@@ -337,6 +338,8 @@ class TestAst < Test::Unit::TestCase
end
def test_node_id_for_location
+ omit if ParserSupport.prism_enabled?
+
exception = begin
raise
rescue => e
@@ -356,6 +359,8 @@ class TestAst < Test::Unit::TestCase
end
def test_of_proc_and_method
+ omit if ParserSupport.prism_enabled? || ParserSupport.prism_enabled_in_subprocess?
+
proc = Proc.new { 1 + 2 }
method = self.method(__method__)
@@ -385,6 +390,8 @@ class TestAst < Test::Unit::TestCase
end
def test_of_backtrace_location
+ omit if ParserSupport.prism_enabled?
+
backtrace_location, lineno = sample_backtrace_location
node = RubyVM::AbstractSyntaxTree.of(backtrace_location)
assert_instance_of(RubyVM::AbstractSyntaxTree::Node, node)
@@ -396,6 +403,8 @@ class TestAst < Test::Unit::TestCase
end
def test_of_proc_and_method_under_eval
+ omit if ParserSupport.prism_enabled?
+
keep_script_lines_back = RubyVM.keep_script_lines
RubyVM.keep_script_lines = false
@@ -425,6 +434,7 @@ class TestAst < Test::Unit::TestCase
end
def test_of_proc_and_method_under_eval_with_keep_script_lines
+ omit if ParserSupport.prism_enabled?
pend if ENV['RUBY_ISEQ_DUMP_DEBUG'] # TODO
keep_script_lines_back = RubyVM.keep_script_lines
@@ -456,6 +466,8 @@ class TestAst < Test::Unit::TestCase
end
def test_of_backtrace_location_under_eval
+ omit if ParserSupport.prism_enabled?
+
keep_script_lines_back = RubyVM.keep_script_lines
RubyVM.keep_script_lines = false
@@ -474,6 +486,7 @@ class TestAst < Test::Unit::TestCase
end
def test_of_backtrace_location_under_eval_with_keep_script_lines
+ omit if ParserSupport.prism_enabled?
pend if ENV['RUBY_ISEQ_DUMP_DEBUG'] # TODO
keep_script_lines_back = RubyVM.keep_script_lines
@@ -696,6 +709,37 @@ class TestAst < Test::Unit::TestCase
assert_equal(:a, args.children[rest])
end
+ def test_return
+ assert_ast_eqaul(<<~STR, <<~EXP)
+ def m(a)
+ return a
+ end
+ STR
+ (SCOPE@1:0-3:3
+ tbl: []
+ args: nil
+ body:
+ (DEFN@1:0-3:3
+ mid: :m
+ body:
+ (SCOPE@1:0-3:3
+ tbl: [:a]
+ args:
+ (ARGS@1:6-1:7
+ pre_num: 1
+ pre_init: nil
+ opt: nil
+ first_post: nil
+ post_num: 0
+ post_init: nil
+ rest: nil
+ kw: nil
+ kwrest: nil
+ block: nil)
+ body: (RETURN@2:2-2:10 (LVAR@2:9-2:10 :a)))))
+ EXP
+ end
+
def test_keep_script_lines_for_parse
node = RubyVM::AbstractSyntaxTree.parse(<<~END, keep_script_lines: true)
1.times do
@@ -736,6 +780,8 @@ dummy
end
def test_keep_script_lines_for_of
+ omit if ParserSupport.prism_enabled?
+
proc = Proc.new { 1 + 2 }
method = self.method(__method__)
@@ -747,6 +793,8 @@ dummy
end
def test_keep_script_lines_for_of_with_existing_SCRIPT_LINES__that_has__FILE__as_a_key
+ omit if ParserSupport.prism_enabled? || ParserSupport.prism_enabled_in_subprocess?
+
# This test confirms that the bug that previously occurred because of
# `AbstractSyntaxTree.of`s unnecessary dependence on SCRIPT_LINES__ does not reproduce.
# The bug occurred only if SCRIPT_LINES__ included __FILE__ as a key.
@@ -814,6 +862,8 @@ dummy
end
def test_e_option
+ omit if ParserSupport.prism_enabled? || ParserSupport.prism_enabled_in_subprocess?
+
assert_in_out_err(["-e", "def foo; end; pp RubyVM::AbstractSyntaxTree.of(method(:foo)).type"],
"", [":SCOPE"], [])
end
@@ -1238,10 +1288,37 @@ dummy
end
end
+ def test_memory_leak
+ assert_no_memory_leak([], "#{<<~"begin;"}", "\n#{<<~'end;'}", rss: true)
+ begin;
+ 1_000_000.times do
+ eval("")
+ end
+ end;
+ end
+
+ def test_locations
+ begin
+ verbose_bak, $VERBOSE = $VERBOSE, false
+ node = RubyVM::AbstractSyntaxTree.parse("1 + 2")
+ ensure
+ $VERBOSE = verbose_bak
+ end
+ locations = node.locations
+
+ assert_equal(RubyVM::AbstractSyntaxTree::Location, locations[0].class)
+ end
+
+ private
+
def assert_error_tolerant(src, expected, keep_tokens: false)
+ assert_ast_eqaul(src, expected, error_tolerant: true, keep_tokens: keep_tokens)
+ end
+
+ def assert_ast_eqaul(src, expected, **options)
begin
verbose_bak, $VERBOSE = $VERBOSE, false
- node = RubyVM::AbstractSyntaxTree.parse(src, error_tolerant: true, keep_tokens: keep_tokens)
+ node = RubyVM::AbstractSyntaxTree.parse(src, **options)
ensure
$VERBOSE = verbose_bak
end
@@ -1251,4 +1328,139 @@ dummy
assert_equal(expected, str)
node
end
+
+ class TestLocation < Test::Unit::TestCase
+ def test_lineno_and_column
+ node = ast_parse("1 + 2")
+ assert_locations(node.locations, [[1, 0, 1, 5]])
+ end
+
+ def test_alias_locations
+ node = ast_parse("alias foo bar")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 13], [1, 0, 1, 5]])
+ end
+
+ def test_and_locations
+ node = ast_parse("1 and 2")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 7], [1, 2, 1, 5]])
+
+ node = ast_parse("1 && 2")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 6], [1, 2, 1, 4]])
+ end
+
+ def test_block_pass_locations
+ node = ast_parse("foo(&bar)")
+ assert_locations(node.children[-1].children[-1].locations, [[1, 4, 1, 8], [1, 4, 1, 5]])
+
+ node = ast_parse("def a(&); b(&) end")
+ assert_locations(node.children[-1].children[-1].children[-1].children[-1].children[-1].locations, [[1, 12, 1, 13], [1, 12, 1, 13]])
+ end
+
+ def test_break_locations
+ node = ast_parse("loop { break 1 }")
+ assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 7, 1, 14], [1, 7, 1, 12]])
+ end
+
+ def test_case_locations
+ node = ast_parse("case a; when 1; end")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 19], [1, 0, 1, 4], [1, 16, 1, 19]])
+ end
+
+ def test_case2_locations
+ node = ast_parse("case; when 1; end")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 17], [1, 0, 1, 4], [1, 14, 1, 17]])
+ end
+
+ def test_case3_locations
+ node = ast_parse("case a; in 1; end")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 17], [1, 0, 1, 4], [1, 14, 1, 17]])
+ end
+
+ def test_next_locations
+ node = ast_parse("loop { next 1 }")
+ assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 7, 1, 13], [1, 7, 1, 11]])
+ end
+
+ def test_or_locations
+ node = ast_parse("1 or 2")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 6], [1, 2, 1, 4]])
+
+ node = ast_parse("1 || 2")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 6], [1, 2, 1, 4]])
+ end
+
+ def test_redo_locations
+ node = ast_parse("loop { redo }")
+ assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 7, 1, 11], [1, 7, 1, 11]])
+ end
+
+ def test_return_locations
+ node = ast_parse("return 1")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 8], [1, 0, 1, 6]])
+
+ node = ast_parse("return")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 6], [1, 0, 1, 6]])
+ end
+
+ def test_unless_locations
+ node = ast_parse("unless cond then 1 else 2 end")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 29], [1, 0, 1, 6], [1, 12, 1, 16], [1, 26, 1, 29]])
+
+ node = ast_parse("1 unless 2")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 10], [1, 2, 1, 8], nil, nil])
+ end
+
+ def test_undef_locations
+ node = ast_parse("undef foo")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 9], [1, 0, 1, 5]])
+
+ node = ast_parse("undef foo, bar")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 14], [1, 0, 1, 5]])
+ end
+
+ def test_valias_locations
+ node = ast_parse("alias $foo $bar")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 15], [1, 0, 1, 5]])
+
+ node = ast_parse("alias $foo $&")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 13], [1, 0, 1, 5]])
+ end
+
+ def test_when_locations
+ node = ast_parse("case a; when 1 then 2; end")
+ assert_locations(node.children[-1].children[1].locations, [[1, 8, 1, 22], [1, 8, 1, 12], [1, 15, 1, 19]])
+ end
+
+ def test_while_locations
+ node = ast_parse("while cond do 1 end")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 19], [1, 0, 1, 5], [1, 16, 1, 19]])
+
+ node = ast_parse("1 while 2")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 9], [1, 2, 1, 7], nil])
+ end
+
+ def test_until_locations
+ node = ast_parse("until cond do 1 end")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 19], [1, 0, 1, 5], [1, 16, 1, 19]])
+
+ node = ast_parse("1 until 2")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 9], [1, 2, 1, 7], nil])
+ end
+
+ private
+ def ast_parse(src, **options)
+ begin
+ verbose_bak, $VERBOSE = $VERBOSE, false
+ RubyVM::AbstractSyntaxTree.parse(src, **options)
+ ensure
+ $VERBOSE = verbose_bak
+ end
+ end
+
+ def assert_locations(locations, expected)
+ ary = locations.map {|loc| loc && [loc.first_lineno, loc.first_column, loc.last_lineno, loc.last_column] }
+
+ assert_equal(ary, expected)
+ end
+ end
end