summaryrefslogtreecommitdiff
path: root/test/ruby/test_compile_prism.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby/test_compile_prism.rb')
-rw-r--r--test/ruby/test_compile_prism.rb138
1 files changed, 131 insertions, 7 deletions
diff --git a/test/ruby/test_compile_prism.rb b/test/ruby/test_compile_prism.rb
index 66986af827..c017111c0a 100644
--- a/test/ruby/test_compile_prism.rb
+++ b/test/ruby/test_compile_prism.rb
@@ -3,6 +3,12 @@
# This file is organized to match itemization in https://github.com/ruby/prism/issues/1335
module Prism
class TestCompilePrism < Test::Unit::TestCase
+ def test_iseq_has_node_id
+ code = "proc { <<END }\n hello\nEND"
+ iseq = RubyVM::InstructionSequence.compile_prism(code)
+ assert_operator iseq.to_a[4][:node_id], :>, -1
+ end
+
# Subclass is used for tests which need it
class Subclass; end
############################################################################
@@ -207,6 +213,12 @@ module Prism
assert_prism_eval("defined?(a(itself))")
assert_prism_eval("defined?(itself(itself))")
+ # method chain with a block on the inside
+ assert_prism_eval("defined?(itself { 1 }.itself)")
+
+ # method chain with parenthesized receiver
+ assert_prism_eval("defined?((itself).itself)")
+
# Method chain on a constant
assert_prism_eval(<<~RUBY)
class PrismDefinedNode
@@ -768,6 +780,9 @@ module Prism
assert_prism_eval("a = [1,2]; [0, *a, 3, 4, *5..6, 7, 8, *9..11]")
assert_prism_eval("[[*1..2], 3, *4..5]")
+ elements = Array.new(64) { ":foo" }
+ assert_prism_eval("[#{elements.join(", ")}, bar: 1, baz: 2]")
+
# Test keyword splat inside of array
assert_prism_eval("[**{x: 'hello'}]")
@@ -842,6 +857,24 @@ module Prism
assert_prism_eval("...2")
assert_prism_eval("1..")
assert_prism_eval("1...")
+ assert_prism_eval("a1 = 1; a2 = 2; a1..a2")
+ assert_prism_eval("a1 = 1; a2 = 2; a1...a2")
+ assert_prism_eval("a2 = 2; ..a2")
+ assert_prism_eval("a2 = 2; ...a2")
+ assert_prism_eval("a1 = 1; a1..")
+ assert_prism_eval("a1 = 1; a1...")
+ assert_prism_eval("1..2; nil")
+ assert_prism_eval("1...2; nil")
+ assert_prism_eval("..2; nil")
+ assert_prism_eval("...2; nil")
+ assert_prism_eval("1..; nil")
+ assert_prism_eval("1...; nil")
+ assert_prism_eval("a1 = 1; a2 = 2; a1..a2; nil")
+ assert_prism_eval("a1 = 1; a2 = 2; a1...a2; nil")
+ assert_prism_eval("a2 = 2; ..a2; nil")
+ assert_prism_eval("a2 = 2; ...a2; nil")
+ assert_prism_eval("a1 = 1; a1..; nil")
+ assert_prism_eval("a1 = 1; a1...; nil")
end
def test_SplatNode
@@ -1013,13 +1046,19 @@ module Prism
end
def test_ForNode
- assert_prism_eval("for i in [1,2] do; i; end")
- assert_prism_eval("for @i in [1,2] do; @i; end")
- assert_prism_eval("for $i in [1,2] do; $i; end")
+ assert_prism_eval("r = []; for i in [1,2] do; r << i; end; r")
+ assert_prism_eval("r = []; for @i in [1,2] do; r << @i; end; r")
+ assert_prism_eval("r = []; for $i in [1,2] do; r << $i; end; r")
- assert_prism_eval("for foo, in [1,2,3] do end")
+ assert_prism_eval("r = []; for foo, in [1,2,3] do r << foo end; r")
- assert_prism_eval("for i, j in {a: 'b'} do; i; j; end")
+ assert_prism_eval("r = []; for i, j in {a: 'b'} do; r << [i, j]; end; r")
+
+ # Test splat node as index in for loop
+ assert_prism_eval("r = []; for *x in [[1,2], [3,4]] do; r << x; end; r")
+ assert_prism_eval("r = []; for * in [[1,2], [3,4]] do; r << 'ok'; end; r")
+ assert_prism_eval("r = []; for x, * in [[1,2], [3,4]] do; r << x; end; r")
+ assert_prism_eval("r = []; for x, *y in [[1,2], [3,4]] do; r << [x, y]; end; r")
end
############################################################################
@@ -1168,6 +1207,27 @@ a
res
RUBY
+
+ # Bug #21001
+ assert_prism_eval(<<~RUBY)
+ RUN_ARRAY = [1,2]
+
+ MAP_PROC = Proc.new do |&blk|
+ block_results = []
+ RUN_ARRAY.each do |value|
+ block_value = blk.call(value)
+ block_results.push block_value
+ end
+ block_results
+ ensure
+ next block_results
+ end
+
+ MAP_PROC.call do |value|
+ break if value > 1
+ next value
+ end
+ RUBY
end
def test_NextNode
@@ -1972,6 +2032,10 @@ end
end
test_prism_call_node
CODE
+
+ # Specialized instructions
+ assert_prism_eval(%{-"literal"})
+ assert_prism_eval(%{"literal".freeze})
end
def test_CallAndWriteNode
@@ -2122,6 +2186,56 @@ end
RUBY
end
+ def test_ForwardingArgumentsNode_instruction_sequence_consistency
+ # Test that both parsers generate identical instruction sequences for forwarding arguments
+ # This prevents regressions like the one fixed in prism_compile.c for PM_FORWARDING_ARGUMENTS_NODE
+
+ # Test case from the bug report: def bar(buz, ...) = foo(buz, ...)
+ source = <<~RUBY
+ def foo(*, &block) = block
+ def bar(buz, ...) = foo(buz, ...)
+ RUBY
+
+ compare_instruction_sequences(source)
+
+ # Test simple forwarding
+ source = <<~RUBY
+ def target(...) = nil
+ def forwarder(...) = target(...)
+ RUBY
+
+ compare_instruction_sequences(source)
+
+ # Test mixed forwarding with regular arguments
+ source = <<~RUBY
+ def target(a, b, c) = [a, b, c]
+ def forwarder(x, ...) = target(x, ...)
+ RUBY
+
+ compare_instruction_sequences(source)
+
+ # Test forwarding with splat
+ source = <<~RUBY
+ def target(a, b, c) = [a, b, c]
+ def forwarder(x, ...); target(*x, ...); end
+ RUBY
+
+ compare_instruction_sequences(source)
+ end
+
+ private
+
+ def compare_instruction_sequences(source)
+ # Get instruction sequences from both parsers
+ parsey_iseq = RubyVM::InstructionSequence.compile_parsey(source)
+ prism_iseq = RubyVM::InstructionSequence.compile_prism(source)
+
+ # Compare instruction sequences
+ assert_equal parsey_iseq.disasm, prism_iseq.disasm
+ end
+
+ public
+
def test_ForwardingSuperNode
assert_prism_eval("class Forwarding; def to_s; super; end; end")
assert_prism_eval("class Forwarding; def eval(code); super { code }; end; end")
@@ -2464,6 +2578,9 @@ end
assert_prism_eval("5 in foo")
assert_prism_eval("1 in 2")
+
+ # Bug: https://bugs.ruby-lang.org/issues/20956
+ assert_prism_eval("1 in [1 | [1]]")
end
def test_MatchRequiredNode
@@ -2502,6 +2619,7 @@ end
assert_prism_eval("module Prism; @prism = 1; 1 in ^@prism; end")
assert_prism_eval("$prism = 1; 1 in ^$prism")
assert_prism_eval("prism = 1; 1 in ^prism")
+ assert_prism_eval("[1].each { 1 => ^it }")
end
############################################################################
@@ -2576,7 +2694,7 @@ end
# Errors #
############################################################################
- def test_MissingNode
+ def test_ErrorRecoveryNode
# TODO
end
@@ -2603,6 +2721,12 @@ end
assert_raise TypeError do
RubyVM::InstructionSequence.compile_file_prism(nil)
end
+
+ assert_nothing_raised(Errno::EMFILE, Errno::ENFILE) do
+ 10000.times do
+ RubyVM::InstructionSequence.compile_file_prism(File::NULL)
+ end
+ end
end
private
@@ -2610,7 +2734,7 @@ end
def compare_eval(source, raw:, location:)
source = raw ? source : "class Prism::TestCompilePrism\n#{source}\nend"
- ruby_eval = RubyVM::InstructionSequence.compile(source).eval
+ ruby_eval = RubyVM::InstructionSequence.compile_parsey(source).eval
prism_eval = RubyVM::InstructionSequence.compile_prism(source).eval
if ruby_eval.is_a? Proc