Fix intermediate array off-by-one error

Co-authored-by: Adam Hess <HParker@github.com>
This commit is contained in:
Kevin Newton 2024-10-04 13:57:14 -04:00
Родитель f77517f473
Коммит 30038656aa
3 изменённых файлов: 53 добавлений и 5 удалений

51
iseq.c
Просмотреть файл

@ -1569,6 +1569,48 @@ iseqw_s_compile(int argc, VALUE *argv, VALUE self)
return iseqw_s_compile_parser(argc, argv, self, rb_ruby_prism_p());
}
/*
* call-seq:
* InstructionSequence.compile_parsey(source[, file[, path[, line[, options]]]]) -> iseq
*
* Takes +source+, which can be a string of Ruby code, or an open +File+ object.
* that contains Ruby source code. It parses and compiles using parse.y.
*
* Optionally takes +file+, +path+, and +line+ which describe the file path,
* real path and first line number of the ruby code in +source+ which are
* metadata attached to the returned +iseq+.
*
* +file+ is used for `__FILE__` and exception backtrace. +path+ is used for
* +require_relative+ base. It is recommended these should be the same full
* path.
*
* +options+, which can be +true+, +false+ or a +Hash+, is used to
* modify the default behavior of the Ruby iseq compiler.
*
* For details regarding valid compile options see ::compile_option=.
*
* RubyVM::InstructionSequence.compile_parsey("a = 1 + 2")
* #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
*
* path = "test.rb"
* RubyVM::InstructionSequence.compile_parsey(File.read(path), path, File.expand_path(path))
* #=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
*
* file = File.open("test.rb")
* RubyVM::InstructionSequence.compile_parsey(file)
* #=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>
*
* path = File.expand_path("test.rb")
* RubyVM::InstructionSequence.compile_parsey(File.read(path), path, path)
* #=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
*
*/
static VALUE
iseqw_s_compile_parsey(int argc, VALUE *argv, VALUE self)
{
return iseqw_s_compile_parser(argc, argv, self, false);
}
/*
* call-seq:
* InstructionSequence.compile_prism(source[, file[, path[, line[, options]]]]) -> iseq
@ -1589,19 +1631,19 @@ iseqw_s_compile(int argc, VALUE *argv, VALUE self)
*
* For details regarding valid compile options see ::compile_option=.
*
* RubyVM::InstructionSequence.compile("a = 1 + 2")
* RubyVM::InstructionSequence.compile_prism("a = 1 + 2")
* #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
*
* path = "test.rb"
* RubyVM::InstructionSequence.compile(File.read(path), path, File.expand_path(path))
* RubyVM::InstructionSequence.compile_prism(File.read(path), path, File.expand_path(path))
* #=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
*
* file = File.open("test.rb")
* RubyVM::InstructionSequence.compile(file)
* RubyVM::InstructionSequence.compile_prism(file)
* #=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>
*
* path = File.expand_path("test.rb")
* RubyVM::InstructionSequence.compile(File.read(path), path, path)
* RubyVM::InstructionSequence.compile_prism(File.read(path), path, path)
* #=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
*
*/
@ -4283,6 +4325,7 @@ Init_ISeq(void)
(void)iseq_s_load;
rb_define_singleton_method(rb_cISeq, "compile", iseqw_s_compile, -1);
rb_define_singleton_method(rb_cISeq, "compile_parsey", iseqw_s_compile_parsey, -1);
rb_define_singleton_method(rb_cISeq, "compile_prism", iseqw_s_compile_prism, -1);
rb_define_singleton_method(rb_cISeq, "compile_file_prism", iseqw_s_compile_file_prism, -1);
rb_define_singleton_method(rb_cISeq, "new", iseqw_s_compile, -1);

Просмотреть файл

@ -6797,6 +6797,8 @@ pm_compile_array_node(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list
// Create the temporary array.
for (; tmp_array_size; tmp_array_size--)
rb_ary_push(tmp_array, pm_static_literal_value(iseq, elements->nodes[index++], scope_node));
index--; // about to be incremented by for loop
OBJ_FREEZE(tmp_array);
// Emit the optimized code.

Просмотреть файл

@ -768,6 +768,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'}]")
@ -2628,7 +2631,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