ruby: vmethod call

develop
jj 2012-05-03 18:49:12 +02:00
parent 8952eabd62
commit ba1e3c4b23
3 changed files with 74 additions and 3 deletions

@ -29,7 +29,7 @@ sub rb_ucase {
my %global_type_renderer = (
'enum-type' => \&render_global_enum,
'struct-type' => \&render_global_class,
'struct-type' => \&render_global_struct,
'class-type' => \&render_global_class,
'bitfield-type' => \&render_global_bitfield,
);
@ -150,7 +150,24 @@ sub render_bitfield_fields {
}
my $cpp_var_counter = 0;
sub render_global_struct {
my ($name, $type) = @_;
my $rbname = rb_ucase($name);
my $cppns = "df::$name";
push @lines_cpp, "}" if @include_cpp;
push @lines_cpp, "void cpp_$name(FILE *fout) {";
push @include_cpp, $name;
push @lines_rb, "class $rbname < MemHack::Compound";
indent_rb {
my $sz = query_cpp("sizeof($cppns)");
push @lines_rb, "sizeof $sz";
render_struct_fields($type, "$cppns");
};
push @lines_rb, "end\n";
}
my %seen_class;
sub render_global_class {
my ($name, $type) = @_;
@ -184,6 +201,8 @@ sub render_global_class {
push @lines_rb, "sizeof $sz";
push @lines_rb, "rtti_classname :$rtti_name" if $rtti_name;
render_struct_fields($type, "$cppns");
my $vms = $type->findnodes('child::virtual-methods')->[0];
render_class_vmethods($vms) if $vms;
};
push @lines_rb, "end\n";
}
@ -206,6 +225,28 @@ sub render_struct_fields {
push @lines_rb, "}";
}
}
sub render_class_vmethods {
my ($vms) = @_;
my $voff = 0;
for my $meth ($vms->findnodes('child::vmethod')) {
my $name = $meth->getAttribute('name');
if ($name) {
my @argnames;
for my $arg ($meth->findnodes('child::ld:field')) {
my $nr = $#argnames + 1;
push @argnames, lcfirst($arg->getAttribute('name') || "arg$nr");
}
push @lines_rb, "def $name(" . join(', ', @argnames) . ')';
indent_rb {
push @lines_rb, "DFHack.vmethod_call(self, $voff" . join('', map { ", $_" } @argnames) . ')'
# TODO interpret return type (eg pointer to vector)
};
push @lines_rb, 'end';
}
$voff += 4;
}
}
sub render_global_objects {
my (@objects) = @_;

@ -191,7 +191,6 @@ class Number < MemStruct
end
end
class Float < MemStruct
# _get/_set defined in ruby.cpp
def _get
DFHack.memory_read_float(@_memaddr)
end
@ -710,6 +709,21 @@ def self.rtti_getvtable(cppname)
v if v != 0
end
def self.vmethod_call(obj, voff, a0=0, a1=0, a2=0, a3=0, a4=0)
vmethod_do_call(obj._memaddr, voff, vmethod_arg(a0), vmethod_arg(a1), vmethod_arg(a2), vmethod_arg(a3))
end
def self.vmethod_arg(arg)
case arg
when nil, false; 0
when true; 1
when Integer; arg
#when String; [arg].pack('p').unpack('L')[0] # raw pointer to buffer
when MemHack::Compound; arg._memaddr
else raise "bad vmethod arg #{arg.class}"
end
end
end

@ -630,6 +630,21 @@ static VALUE rb_dfmemory_bitarray_set(VALUE self, VALUE addr, VALUE idx, VALUE v
}
/* call an arbitrary object virtual method */
static VALUE rb_dfvcall(VALUE self, VALUE cppobj, VALUE cppvoff, VALUE a0, VALUE a1, VALUE a2, VALUE a3)
{
#ifdef WIN32
__thiscall
#endif
int (*fptr)(char **me, int, int, int, int);
char **that = (char**)rb_num2ulong(cppobj);
int ret;
fptr = (decltype(fptr))*(void**)(*that + rb_num2ulong(cppvoff));
ret = fptr(that, rb_num2ulong(a0), rb_num2ulong(a1), rb_num2ulong(a2), rb_num2ulong(a3));
return rb_uint2inum(ret);
}
// define module DFHack and its methods
static void ruby_bind_dfhack(void) {
@ -649,6 +664,7 @@ static void ruby_bind_dfhack(void) {
rb_define_singleton_method(rb_cDFHack, "print_err", RUBY_METHOD_FUNC(rb_dfprint_err), 1);
rb_define_singleton_method(rb_cDFHack, "malloc", RUBY_METHOD_FUNC(rb_dfmalloc), 1);
rb_define_singleton_method(rb_cDFHack, "free", RUBY_METHOD_FUNC(rb_dffree), 1);
rb_define_singleton_method(rb_cDFHack, "vmethod_do_call", RUBY_METHOD_FUNC(rb_dfvcall), 6);
rb_define_const(rb_cDFHack, "REBASE_DELTA", rb_dfrebase_delta());
rb_define_singleton_method(rb_cDFHack, "memory_read", RUBY_METHOD_FUNC(rb_dfmemory_read), 2);