1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

support all locals for cexpr!, cstmt!

Primitve.cexpr! and .cstmt! can access Ruby's parameter and
*local variables* (note that local parameters are also local
variables). However recent changes only allow to access
parameters. This patch fix it.

For example, the following code can work:

def foo a, b, k: :kw, **kwrest
  c = a + b
  d = k
  e = kwrest
  p Primitive.cstmt!(%q(rb_p(rb_ary_new_from_args(5, a, b, c, d, e));
                        return Qnil;))
end
This commit is contained in:
Koichi Sasada 2020-07-04 17:23:34 +09:00
parent 7a5da7d55d
commit 74e1bca79d

View file

@ -49,37 +49,28 @@ def make_cfunc_name inlines, name, lineno
end end
end end
def collect_params tree def collect_locals tree
while tree type, name, (line, cols) = tree
case tree.first if locals = LOCALS_DB[[name, line]]
when :params locals
params = []
_, mand, opt, rest, post, kwds, kwrest, block = tree
mand.each {|_, v| params << v.to_sym} if mand
opt.each {|(_, v), | params << v.to_sym} if opt
params << rest[1][1].to_sym if rest
post.each {|_, v| params << v.to_sym} if post
params << kwrest[1][1].to_sym if kwrest
params << block[1][1].to_sym if block
return params
when :paren
tree = tree[1]
else else
raise "unknown sexp: #{tree.first}" if false # for debugging
pp LOCALS_DB
raise "not found: [#{name}, #{line}]"
end end
end end
end end
def collect_builtin base, tree, name, bs, inlines, params = nil def collect_builtin base, tree, name, bs, inlines, locals = nil
while tree while tree
call = recv = sep = mid = args = nil call = recv = sep = mid = args = nil
case tree.first case tree.first
when :def when :def
params = collect_params(tree[2]) locals = collect_locals(tree[1])
tree = tree[3] tree = tree[3]
next next
when :defs when :defs
params = collect_params(tree[4]) locals = collect_locals(tree[3])
tree = tree[5] tree = tree[5]
next next
when :class when :class
@ -146,7 +137,7 @@ def collect_builtin base, tree, name, bs, inlines, params = nil
func_name = "_bi#{inlines.size}" func_name = "_bi#{inlines.size}"
cfunc_name = make_cfunc_name(inlines, name, lineno) cfunc_name = make_cfunc_name(inlines, name, lineno)
inlines[cfunc_name] = [lineno, text, params, func_name] inlines[cfunc_name] = [lineno, text, locals, func_name]
argc -= 1 argc -= 1
when 'cexpr', 'cconst' when 'cexpr', 'cconst'
text = inline_text argc, args.first text = inline_text argc, args.first
@ -155,8 +146,8 @@ def collect_builtin base, tree, name, bs, inlines, params = nil
func_name = "_bi#{inlines.size}" func_name = "_bi#{inlines.size}"
cfunc_name = make_cfunc_name(inlines, name, lineno) cfunc_name = make_cfunc_name(inlines, name, lineno)
params = [] if $1 == 'cconst' locals = [] if $1 == 'cconst'
inlines[cfunc_name] = [lineno, code, params, func_name] inlines[cfunc_name] = [lineno, code, locals, func_name]
argc -= 1 argc -= 1
when 'cinit' when 'cinit'
text = inline_text argc, args.first text = inline_text argc, args.first
@ -177,21 +168,53 @@ def collect_builtin base, tree, name, bs, inlines, params = nil
end end
tree.each do |t| tree.each do |t|
collect_builtin base, t, name, bs, inlines, params if Array === t collect_builtin base, t, name, bs, inlines, locals if Array === t
end end
break break
end end
end end
# ruby mk_builtin_loader.rb TARGET_FILE.rb # ruby mk_builtin_loader.rb TARGET_FILE.rb
# #=> generate TARGET_FILE.rbinc # #=> generate TARGET_FILE.rbinc
# #
LOCALS_DB = {} # [method_name, first_line] = locals
def collect_iseq iseq_ary
# iseq_ary.each_with_index{|e, i| p [i, e]}
label = iseq_ary[5]
first_line = iseq_ary[8]
type = iseq_ary[9]
locals = iseq_ary[10]
insns = iseq_ary[13]
if type == :method
LOCALS_DB[[label, first_line].freeze] = locals
end
insns.each{|insn|
case insn
when Integer
# ignore
when Array
# p insn.shift # insn name
insn.each{|op|
if Array === op && op[0] == "YARVInstructionSequence/SimpleDataFormat"
collect_iseq op
end
}
end
}
end
def mk_builtin_header file def mk_builtin_header file
base = File.basename(file, '.rb') base = File.basename(file, '.rb')
ofile = "#{file}inc" ofile = "#{file}inc"
# bs = { func_name => argc } # bs = { func_name => argc }
collect_builtin(base, Ripper.sexp(File.read(file)), 'top', bs = {}, inlines = {}) code = File.read(file)
collect_iseq RubyVM::InstructionSequence.compile(code).to_a
collect_builtin(base, Ripper.sexp(code), 'top', bs = {}, inlines = {})
begin begin
f = open(ofile, 'w') f = open(ofile, 'w')
@ -219,12 +242,12 @@ def mk_builtin_header file
lineno = __LINE__ - lineno - 1 lineno = __LINE__ - lineno - 1
line_file = file line_file = file
inlines.each{|cfunc_name, (body_lineno, text, params, func_name)| inlines.each{|cfunc_name, (body_lineno, text, locals, func_name)|
if String === cfunc_name if String === cfunc_name
f.puts "static VALUE #{cfunc_name}(struct rb_execution_context_struct *ec, const VALUE self) {" f.puts "static VALUE #{cfunc_name}(struct rb_execution_context_struct *ec, const VALUE self) {"
lineno += 1 lineno += 1
params.reverse_each.with_index{|param, i| locals.reverse_each.with_index{|param, i|
next unless Symbol === param next unless Symbol === param
f.puts "MAYBE_UNUSED(const VALUE) #{param} = rb_vm_lvar(ec, #{-3 - i});" f.puts "MAYBE_UNUSED(const VALUE) #{param} = rb_vm_lvar(ec, #{-3 - i});"
lineno += 1 lineno += 1