ruby: patron for memory primitives

develop
jj 2012-04-06 19:30:58 +02:00
parent fb1b424cbf
commit 52007e0d4f
2 changed files with 226 additions and 7 deletions

@ -46,11 +46,13 @@ my %item_renderer = (
); );
my %seen_enum_name;
sub render_global_enum { sub render_global_enum {
my ($name, $type) = @_; my ($name, $type) = @_;
my $rbname = rb_ucase($name); my $rbname = rb_ucase($name);
push @lines_rb, "class $rbname"; push @lines_rb, "class $rbname";
%seen_enum_name = ();
indent_rb { indent_rb {
render_enum_fields($type); render_enum_fields($type);
}; };
@ -66,6 +68,8 @@ sub render_enum_fields {
if ($elemname) { if ($elemname) {
my $rbelemname = rb_ucase($elemname); my $rbelemname = rb_ucase($elemname);
$rbelemname .= '_' while ($seen_enum_name{$rbelemname});
$seen_enum_name{$rbelemname}++;
push @lines_rb, "$rbelemname = $value"; push @lines_rb, "$rbelemname = $value";
} }
} }
@ -76,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 < MemStruct"; push @lines_rb, "class $rbname < Compound";
indent_rb { indent_rb {
render_bitfield_fields($type); render_bitfield_fields($type);
}; };
@ -92,19 +96,33 @@ sub render_bitfield_fields {
$name = $field->getAttribute('ld:anon-name') if (!$name); $name = $field->getAttribute('ld:anon-name') if (!$name);
print "bitfield $name !number\n" if (!($field->getAttribute('ld:meta') eq 'number')); print "bitfield $name !number\n" if (!($field->getAttribute('ld:meta') eq 'number'));
if ($count == 1) { if ($count == 1) {
push @lines_rb, "bit :$name, $shift" if ($name); push @lines_rb, "field(:$name, 0) { bit $shift }" if ($name);
} else { } else {
push @lines_rb, "bits :$name, $shift, $count" if ($name); push @lines_rb, "field(:$name, 0) { bits $shift, $count }" if ($name);
} }
$shift += $count; $shift += $count;
} }
} }
my %global_types;
my $cpp_var_counter = 0; my $cpp_var_counter = 0;
my %seen_class;
sub render_global_class { sub render_global_class {
my ($name, $type) = @_; my ($name, $type) = @_;
my $rbname = rb_ucase($name);
# ensure pre-definition of ancestors
my $parent = $type->getAttribute('inherits-from');
render_global_class($parent, $global_types{$parent}) if ($parent and !$seen_class{$parent});
return if $seen_class{$name};
$seen_class{$name}++;
%seen_enum_name = ();
my $rbparent = ($parent ? rb_ucase($parent) : 'Compound');
my $cppvar = "v_$cpp_var_counter"; my $cppvar = "v_$cpp_var_counter";
$cpp_var_counter++; $cpp_var_counter++;
push @lines_cpp, "}" if @include_cpp; push @lines_cpp, "}" if @include_cpp;
@ -112,9 +130,7 @@ sub render_global_class {
push @lines_cpp, " df::$name *$cppvar = (df::$name*)moo;"; push @lines_cpp, " df::$name *$cppvar = (df::$name*)moo;";
push @include_cpp, $name; push @include_cpp, $name;
my $rbname = rb_ucase($name); push @lines_rb, "class $rbname < $rbparent";
my $parent = rb_ucase($type->getAttribute('inherits-from') || 'MemStruct');
push @lines_rb, "class $rbname < $parent";
indent_rb { indent_rb {
render_struct_fields($type, "(*$cppvar)"); render_struct_fields($type, "(*$cppvar)");
}; };
@ -343,7 +359,6 @@ if ($offsetfile) {
my $doc = XML::LibXML->new()->parse_file($input); my $doc = XML::LibXML->new()->parse_file($input);
my %global_types;
$global_types{$_->getAttribute('type-name')} = $_ foreach $doc->findnodes('/ld:data-definition/ld:global-type'); $global_types{$_->getAttribute('type-name')} = $_ foreach $doc->findnodes('/ld:data-definition/ld:global-type');
for my $name (sort { $a cmp $b } keys %global_types) { for my $name (sort { $a cmp $b } keys %global_types) {
@ -385,6 +400,10 @@ if ($output =~ /\.cpp$/) {
print FH " return 0;\n"; print FH " return 0;\n";
print FH "}\n"; print FH "}\n";
} else { } else {
print FH "module DFHack\n";
print FH "module MemHack\n";
print FH "$_\n" for @lines_rb; print FH "$_\n" for @lines_rb;
print FH "end\n";
print FH "end\n";
} }
close FH; close FH;

@ -0,0 +1,200 @@
module DFHack
module MemHack
class MemStruct
attr_accessor :_memaddr
def _at(addr) ; @_memaddr = addr ; self ; end
def _get ; self ; end
end
class Compound < MemStruct
class << self
attr_accessor :_fields
def field(name, offset)
struct = yield
@_fields ||= []
@_fields << [name, offset, struct]
define_method(name) { struct._at(@_memaddr+offset)._get }
define_method("#{name}=") { |v| struct._at(@_memaddr+offset)._set(v) }
end
def number(bits, signed)
Number.new(bits, signed)
end
def float
Float.new
end
def bit(shift)
BitField.new(shift, 1)
end
def bits(shift, len)
BitField.new(shift, len)
end
def pointer(tglen=nil)
Pointer.new(tglen, (yield if tglen))
end
def static_array(len, tglen)
StaticArray.new(tglen, len, yield)
end
def static_string(len)
StaticString.new(len)
end
def stl_vector(tglen=nil)
StlVector.new(tglen, (yield if tglen))
end
def stl_string
StlString.new
end
def stl_bit_vector
StlBitVector.new
end
def stl_deque(tglen=nil)
StlDeque.new(tglen, (yield if tglen))
end
def df_flagarray
DfFlagarray.new
end
def df_array(tglen=nil)
DfArray.new(tglen, (yield if tglen))
end
def df_linked_list
DfLinkedList.new((yield if block_given?))
end
def global(glob)
Global.new(glob)
end
def compound(&b)
m = Class.new(Compound)
m.instance_eval(&b)
m
end
end
def _set(h) ; h.each { |k, v| send("_#{k}=", v) } ; end
end
class Number < MemStruct
attr_accessor :_bits, :_signed
def initialize(bits, signed)
@_bits = bits
@_signed = signed
end
end
class Float < MemStruct
end
class BitField < Number
attr_accessor :_shift, :_len
def initialize(shift, len)
@_shift = shift
@_len = len
super(32, false)
end
def _get(whole=false)
v = super()
return v if whole
v = (v >> @_shift) % (1 << @_len)
if @_len == 1
v == 0 ? false : true
else
v
end
end
def _set(v)
if @_len == 1
v = (v && v != 0 ? 1 : 0)
end
v = ((v % (1 << @_len)) << @_shift)
ori = _get(true)
super(ori - (ori & (-1 % (1 << @_len)) << @_shift) + v)
end
end
class Pointer < MemStruct
attr_accessor :_tglen, :_tg
def initialize(tglen, tg)
@_tglen = tglen
@_tg = tg
end
end
class StaticArray < MemStruct
attr_accessor :_tglen, :_length, :_tg
def initialize(tglen, length, tg)
@_tglen = tglen
@_length = length
@_tg = tg
end
def _set(a) ; a.each_with_index { |v, i| self[i] = v } ; end
alias length _length
alias size _length
def _tgat(i)
tg._at(@_memaddr + i*@_tglen)
end
def [](i)
if (i > 0) or (@_length and i < @_length)
tgat(i)._get
end
end
def []=(i, v)
if (i > 0) or (@_length and i < @_length)
tgat(i)._set
end
end
end
class StaticString < MemStruct
attr_accessor :_length
def initialize(length)
@_length = length
end
end
class StlVector < MemStruct
attr_accessor :_tglen, :_tg
def initialize(tglen, tg)
@_tglen = tglen
@_tg = tg
end
end
class StlString < MemStruct
end
class StlBitVector < MemStruct
end
class StlDeque < MemStruct
attr_accessor :_tglen, :_tg
def initialize(tglen, tg)
@_tglen = tglen
@_tg = tg
end
end
class DfFlagarray < MemStruct
end
class DfArray < MemStruct
attr_accessor :_tglen, :_tg
def initialize(tglen, tg)
@_tglen = tglen
@_tg = tg
end
end
class DfLinkedList < MemStruct
attr_accessor :_tg
def initialize(tg)
@_tg = tg
end
end
class Global < MemStruct
attr_accessor :_glob
def initialize(glob)
@_glob = glob
end
def _at(addr) ; g = const_get(@_glob) ; g._at(addr) ; end
end
end
end
require 'ruby-autogen'