ruby: add df_array, pointer_ary, move generated classes in DFHack

develop
jj 2012-04-20 01:29:52 +02:00
parent a450e9ddeb
commit 0952b76173
3 changed files with 115 additions and 53 deletions

@ -51,8 +51,7 @@ sub render_global_enum {
my ($name, $type) = @_; my ($name, $type) = @_;
my $rbname = rb_ucase($name); my $rbname = rb_ucase($name);
# store constants in DFHack::EnumName and not in DFHack::MemHack::EnumName push @lines_rb, "class $rbname";
push @lines_rb, "class ::DFHack::$rbname";
%seen_enum_name = (); %seen_enum_name = ();
indent_rb { indent_rb {
render_enum_fields($type); render_enum_fields($type);
@ -81,7 +80,7 @@ sub render_global_bitfield {
my ($name, $type) = @_; my ($name, $type) = @_;
my $rbname = rb_ucase($name); my $rbname = rb_ucase($name);
push @lines_rb, "class $rbname < Compound"; push @lines_rb, "class $rbname < MemHack::Compound";
indent_rb { indent_rb {
render_bitfield_fields($type); render_bitfield_fields($type);
}; };
@ -142,7 +141,7 @@ sub render_global_class {
} }
} }
my $rbparent = ($parent ? rb_ucase($parent) : 'Compound'); my $rbparent = ($parent ? rb_ucase($parent) : 'MemHack::Compound');
my $cppvar = "v_$cpp_var_counter"; my $cppvar = "v_$cpp_var_counter";
$cpp_var_counter++; $cpp_var_counter++;
@ -191,7 +190,7 @@ sub render_global_objects {
push @lines_cpp, "void cpp_$sname(FILE *fout) {"; push @lines_cpp, "void cpp_$sname(FILE *fout) {";
push @include_cpp, $sname; push @include_cpp, $sname;
push @lines_rb, "class $rbname < Compound"; push @lines_rb, "class $rbname < MemHack::Compound";
indent_rb { indent_rb {
for my $obj (@objects) { for my $obj (@objects) {
my $oname = $obj->getAttribute('name'); my $oname = $obj->getAttribute('name');
@ -208,7 +207,6 @@ sub render_global_objects {
}; };
push @lines_rb, "end"; push @lines_rb, "end";
push @lines_rb, "module ::DFHack";
indent_rb { indent_rb {
push @lines_rb, "Global = GlobalObjects.new._at(0)"; push @lines_rb, "Global = GlobalObjects.new._at(0)";
for my $obj (@global_objects) { for my $obj (@global_objects) {
@ -216,7 +214,6 @@ sub render_global_objects {
push @lines_rb, "def self.$obj=(v) ; Global.$obj = v ; end"; push @lines_rb, "def self.$obj=(v) ; Global.$obj = v ; end";
} }
}; };
push @lines_rb, "end";
} }
@ -325,8 +322,13 @@ sub render_item_pointer {
my ($item, $cppvar) = @_; my ($item, $cppvar) = @_;
my $tg = $item->findnodes('child::ld:item')->[0]; my $tg = $item->findnodes('child::ld:item')->[0];
my $ary = $item->getAttribute('is-array');
if ($ary and $ary eq 'true') {
my $tglen = get_tglen($tg, $cppvar); my $tglen = get_tglen($tg, $cppvar);
push @lines_rb, "pointer($tglen) {"; push @lines_rb, "pointer_ary($tglen) {";
} else {
push @lines_rb, "pointer {";
}
indent_rb { indent_rb {
render_item($tg, "${cppvar}[0]"); render_item($tg, "${cppvar}[0]");
}; };
@ -468,15 +470,13 @@ if ($output =~ /\.cpp$/) {
print FH "}\n"; print FH "}\n";
} else { } else {
print FH "module DFHack\n";
print FH "module MemHack\n";
if ($memstruct) { if ($memstruct) {
open MH, "<$memstruct"; open MH, "<$memstruct";
print FH "$_" while(<MH>); print FH "$_" while(<MH>);
close MH; close MH;
} }
print FH "module DFHack\n";
print FH "$_\n" for @lines_rb; print FH "$_\n" for @lines_rb;
print FH "end\n"; print FH "end\n";
print FH "end\n";
} }
close FH; close FH;

@ -1,6 +1,8 @@
module DFHack
module MemHack
class MemStruct class MemStruct
attr_accessor :_memaddr attr_accessor :_memaddr
def _at(addr) ; @_memaddr = addr ; self ; end def _at(addr) ; @_memaddr = addr ; dup ; end
def _get ; self ; end def _get ; self ; end
end end
@ -27,8 +29,11 @@ class Compound < MemStruct
def bits(shift, len) def bits(shift, len)
BitField.new(shift, len) BitField.new(shift, len)
end end
def pointer(tglen=nil) def pointer
Pointer.new(tglen, (yield if tglen)) Pointer.new((yield if block_given?))
end
def pointer_ary(tglen)
PointerAry.new(tglen, yield)
end end
def static_array(len, tglen) def static_array(len, tglen)
StaticArray.new(tglen, len, yield) StaticArray.new(tglen, len, yield)
@ -80,6 +85,7 @@ class Compound < MemStruct
end end
def _set(h) ; h.each { |k, v| send("_#{k}=", v) } ; end def _set(h) ; h.each { |k, v| send("_#{k}=", v) } ; end
end end
class Number < MemStruct class Number < MemStruct
attr_accessor :_bits, :_signed attr_accessor :_bits, :_signed
def initialize(bits, signed) def initialize(bits, signed)
@ -149,6 +155,23 @@ class BitField < MemStruct
end end
class Pointer < MemStruct class Pointer < MemStruct
attr_accessor :_tg
def initialize(tg)
@_tg = tg
end
def _getp
DFHack.memory_read_int32(@_memaddr) & 0xffffffff
end
# the pointer is invisible, forward all methods to the pointed object
def method_missing(*a)
addr = _getp
tg = (addr == 0 ? nil : @_tg._at(addr)._get)
tg.send(*a)
end
end
class PointerAry < MemStruct
attr_accessor :_tglen, :_tg attr_accessor :_tglen, :_tg
def initialize(tglen, tg) def initialize(tglen, tg)
@_tglen = tglen @_tglen = tglen
@ -159,10 +182,6 @@ class Pointer < MemStruct
delta = (i != 0 ? i*@_tglen : 0) delta = (i != 0 ? i*@_tglen : 0)
(DFHack.memory_read_int32(@_memaddr) & 0xffffffff) + delta (DFHack.memory_read_int32(@_memaddr) & 0xffffffff) + delta
end end
def _setp(v)
DFHack.memory_write_int32(@_memaddr, v)
end
def _get ; self ; end
def [](i) def [](i)
addr = _getp(i) addr = _getp(i)
@ -174,11 +193,6 @@ class Pointer < MemStruct
raise 'null pointer' if addr == 0 raise 'null pointer' if addr == 0
@_tg._at(addr)._set(v) @_tg._at(addr)._set(v)
end end
# the pointer is invisible, forward all methods to the pointed object
def method_missing(*a)
self[0].send(*a)
end
end end
class StaticArray < MemStruct class StaticArray < MemStruct
attr_accessor :_tglen, :_length, :_tg attr_accessor :_tglen, :_length, :_tg
@ -205,7 +219,7 @@ class StaticArray < MemStruct
end end
include Enumerable include Enumerable
def each; (0...length).each { |i| yield self[i] }; end def each ; (0...length).each { |i| yield self[i] } ; end
end end
class StaticString < MemStruct class StaticString < MemStruct
attr_accessor :_length attr_accessor :_length
@ -274,8 +288,9 @@ class StlVector32 < MemStruct
end end
v v
end end
include Enumerable include Enumerable
def each; (0...length).each { |i| yield self[i] }; end def each ; (0...length).each { |i| yield self[i] } ; end
end end
class StlVector16 < StlVector32 class StlVector16 < StlVector32
def length def length
@ -346,19 +361,41 @@ class StlDeque < MemStruct
@_tglen = tglen @_tglen = tglen
@_tg = tg @_tg = tg
end end
# TODO
end end
class DfFlagarray < MemStruct class DfFlagarray < MemStruct
# TODO # TODO
end end
class DfArray < MemStruct class DfArray < Compound
attr_accessor :_tglen, :_tg attr_accessor :_tglen, :_tg
def initialize(tglen, tg) def initialize(tglen, tg)
@_tglen = tglen @_tglen = tglen
@_tg = tg @_tg = tg
end end
# TODO field(:_length, 0) { number 32, false }
field(:_ptr, 4) { number 32, false }
def length ; _length ; end
def size ; _length ; end
def _tgat(i)
@_tg._at(_ptr + i*@_tglen) if i >= 0 and i < _length
end
def [](i)
i += _length if i < 0
_tgat(i)._get
end
def []=(i, v)
i += _length if i < 0
_tgat(i)._set(v)
end
def _set(a)
a.each_with_index { |v, i| self[i] = v }
end
include Enumerable
def each ; (0...length).each { |i| yield self[i] } ; end
end end
class DfLinkedList < MemStruct class DfLinkedList < MemStruct
attr_accessor :_tg attr_accessor :_tg
@ -373,33 +410,60 @@ class Global < MemStruct
@_glob = glob @_glob = glob
end end
def _at(addr) def _at(addr)
g = DFHack::MemHack.const_get(@_glob) g = DFHack.const_get(@_glob)
g = DFHack.rtti_getclass(g, addr) g = DFHack.rtti_getclassat(g, addr)
g.new._at(addr) g.new._at(addr)
end end
end end
end # module MemHack
# cpp rtti name -> rb class
@rtti_n2c = {}
@rtti_c2n = {}
module ::DFHack # vtableptr -> cpp rtti name (cache)
def self.rtti_register(cname, cls) @rtti_n2v = {}
@rtti_n2c ||= {} @rtti_v2n = {}
@rtti_class ||= {}
def self.rtti_n2c ; @rtti_n2c ; end
def self.rtti_c2n ; @rtti_c2n ; end
# register a ruby class with a cpp rtti class name
def self.rtti_register(cname, cls)
@rtti_n2c[cname] = cls @rtti_n2c[cname] = cls
@rtti_class[cls] = true @rtti_c2n[cls] = cname
end end
# return the ruby class to use for a given address if rtti info is available # return the ruby class to use for the cpp object at address if rtti info is available
def self.rtti_getclass(cls, addr) def self.rtti_getclassat(cls, addr)
@rtti_n2c ||= {} if addr != 0 and @rtti_c2n[cls]
@rtti_class ||= {} # rtti info exist for class => cpp object has a vtable
if addr != 0 and @rtti_class[cls]
@rtti_n2c[rtti_readclassname(get_vtable_ptr(addr))] || cls @rtti_n2c[rtti_readclassname(get_vtable_ptr(addr))] || cls
else else
cls cls
end end
end end
def self.rtti_readclassname(vptr) # try to read the rtti classname from an object vtable pointer
@rtti_v2n ||= {} def self.rtti_readclassname(vptr)
@rtti_v2n[vptr] ||= get_rtti_classname(vptr) unless n = @rtti_v2n[vptr]
n = @rtti_v2n[vptr] = get_rtti_classname(vptr)
@rtti_n2v[n] = vptr
end end
n
end end
# return the vtable pointer from the cpp rtti name
def self.rtti_getvtable(cname)
unless v = @rtti_n2v[cname]
v = get_vtable(cname)
@rtti_n2v[cname] = v
@rtti_v2n[v] = cname if v != 0
end
v if v != 0
end
end

@ -370,14 +370,12 @@ static VALUE rb_dfregister(VALUE self, VALUE name, VALUE descr)
static VALUE rb_dfget_global_address(VALUE self, VALUE name) static VALUE rb_dfget_global_address(VALUE self, VALUE name)
{ {
uint32_t addr = Core::getInstance().vinfo->getAddress(rb_string_value_ptr(&name)); return rb_uint2inum(Core::getInstance().vinfo->getAddress(rb_string_value_ptr(&name)));
return rb_uint2inum(addr);
} }
static VALUE rb_dfget_vtable(VALUE self, VALUE name) static VALUE rb_dfget_vtable(VALUE self, VALUE name)
{ {
uint32_t addr = (uint32_t)Core::getInstance().vinfo->getVTable(rb_string_value_ptr(&name)); return rb_uint2inum((uint32_t)Core::getInstance().vinfo->getVTable(rb_string_value_ptr(&name)));
return rb_uint2inum(addr);
} }
// read the c++ class name from a vtable pointer, inspired from doReadClassName // read the c++ class name from a vtable pointer, inspired from doReadClassName