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:
parent
7a5da7d55d
commit
74e1bca79d
1 changed files with 50 additions and 27 deletions
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue