ruby: interpret types in vmethod signatures

develop
jj 2012-05-11 01:34:03 +02:00
parent 607cd9c8f2
commit dfe86f9bd7
2 changed files with 54 additions and 4 deletions

@ -40,7 +40,7 @@ Set a custom nickname to unit with id '123'
df.find_unit(123).name.nickname = 'moo'
Show current unit profession
p DFHack::Profession::ENUM[df.find_unit.profession]
p df.find_unit.profession
Center the screen on unit '123'
df.center_viewscreen(df.find_unit(123))

@ -234,14 +234,23 @@ sub render_class_vmethods {
my $name = $meth->getAttribute('name');
if ($name) {
my @argnames;
my @argargs;
for my $arg ($meth->findnodes('child::ld:field')) {
my $nr = $#argnames + 1;
push @argnames, lcfirst($arg->getAttribute('name') || "arg$nr");
my $argname = lcfirst($arg->getAttribute('name') || "arg$nr");
push @argnames, $argname;
if ($arg->getAttribute('ld:meta') eq 'global' and $arg->getAttribute('ld:subtype') eq 'enum') {
push @argargs, rb_ucase($arg->getAttribute('type-name')) . ".to_i($argname)";
} else {
push @argargs, $argname;
}
}
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)
my $args = join('', map { ", $_" } @argargs);
my $call = "DFHack.vmethod_call(self, $voff$args)";
my $ret = $meth->findnodes('child::ret-type')->[0];
render_class_vmethod_ret($call, $ret);
};
push @lines_rb, 'end';
}
@ -251,6 +260,47 @@ sub render_class_vmethods {
}
}
sub render_class_vmethod_ret {
my ($call, $ret) = @_;
if (!$ret) {
push @lines_rb, "$call ; nil";
return;
}
my $retmeta = $ret->getAttribute('ld:meta') || '';
if ($retmeta eq 'global') { # enum
my $retname = $ret->getAttribute('type-name');
if ($retname and $global_types{$retname} and
$global_types{$retname}->getAttribute('ld:meta') eq 'enum-type') {
push @lines_rb, rb_ucase($retname) . ".to_sym($call)";
} else {
print "vmethod global nonenum $call\n";
push @lines_rb, $call;
}
} elsif ($retmeta eq 'number') {
my $retsubtype = $ret->getAttribute('ld:subtype');
my $retbits = $ret->getAttribute('ld:bits');
push @lines_rb, "val = $call";
if ($retsubtype eq 'bool') {
push @lines_rb, "(val & 1) != 0";
} elsif ($ret->getAttribute('ld:unsigned')) {
push @lines_rb, "val & ((1 << $retbits) - 1)";
} else { # signed
push @lines_rb, "val &= ((1 << $retbits) - 1)";
push @lines_rb, "((val >> ($retbits-1)) & 1) == 0 ? val : val - (1 << $retbits)";
}
} elsif ($retmeta eq 'pointer') {
push @lines_rb, "ptr = $call";
push @lines_rb, "class << self";
indent_rb {
render_item($ret->findnodes('child::ld:item')->[0]);
};
push @lines_rb, "end._at(ptr) if ptr != 0";
} else {
print "vmethod unkret $call\n";
push @lines_rb, $call;
}
}
sub render_global_objects {
my (@objects) = @_;
my @global_objects;