rb codegen: generate ruby
parent
57f2e189ee
commit
ca528fff35
@ -0,0 +1,175 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use XML::LibXML;
|
||||
|
||||
our @lines_rb;
|
||||
our @lines_cpp;
|
||||
|
||||
sub indent_rb(&) {
|
||||
my ($sub) = @_;
|
||||
my @lines;
|
||||
{
|
||||
local @lines_rb;
|
||||
$sub->();
|
||||
@lines = map { " " . $_ } @lines_rb;
|
||||
}
|
||||
push @lines_rb, @lines
|
||||
}
|
||||
|
||||
sub rb_ucase {
|
||||
my ($name) = @_;
|
||||
return join("", map { ucfirst $_ } (split('_', $name)));
|
||||
}
|
||||
|
||||
my %render_struct_field = (
|
||||
'global' => \&render_field_global,
|
||||
'number' => \&render_field_number,
|
||||
'container' => \&render_field_container,
|
||||
);
|
||||
|
||||
my %render_global_type = (
|
||||
'enum-type' => \&render_global_enum,
|
||||
'struct-type' => \&render_global_class,
|
||||
'class-type' => \&render_global_class,
|
||||
'bitfield-type' => \&render_global_bitfield,
|
||||
);
|
||||
|
||||
sub render_global_enum {
|
||||
my ($name, $type) = @_;
|
||||
my $value = -1;
|
||||
|
||||
my $rbname = rb_ucase($name);
|
||||
push @lines_rb, "class $rbname";
|
||||
indent_rb {
|
||||
for my $item ($type->findnodes('child::enum-item')) {
|
||||
$value = $item->getAttribute('value') || ($value+1);
|
||||
my $elemname = $item->getAttribute('name'); # || "unk_$value";
|
||||
|
||||
if ($elemname) {
|
||||
my $rbelemname = rb_ucase($elemname);
|
||||
push @lines_rb, "$rbelemname = $value";
|
||||
}
|
||||
}
|
||||
};
|
||||
push @lines_rb, "end";
|
||||
}
|
||||
|
||||
sub render_global_bitfield {
|
||||
my ($name, $type) = @_;
|
||||
|
||||
my $rbname = rb_ucase($name);
|
||||
push @lines_rb, "class $rbname < MemStruct";
|
||||
indent_rb {
|
||||
my $shift = 0;
|
||||
for my $field ($type->findnodes('child::ld:field')) {
|
||||
my $count = $field->getAttribute('count') || 1;
|
||||
print "bitfield $name !number\n" if (!($field->getAttribute('ld:meta') eq 'number'));
|
||||
my $fname = $field->getAttribute('name');
|
||||
push @lines_rb, "bits :$fname, $shift, $count" if ($fname);
|
||||
$shift += $count;
|
||||
}
|
||||
};
|
||||
push @lines_rb, "end";
|
||||
}
|
||||
|
||||
sub render_global_class {
|
||||
my ($name, $type) = @_;
|
||||
|
||||
#my $cppvar = 'v'; # for offsetof
|
||||
|
||||
my $rbname = rb_ucase($name);
|
||||
my $parent = rb_ucase($type->getAttribute('inherits-from') || 'MemStruct');
|
||||
push @lines_rb, "class $rbname < $parent";
|
||||
indent_rb {
|
||||
render_struct_fields($type);
|
||||
};
|
||||
push @lines_rb, "end";
|
||||
}
|
||||
|
||||
sub render_field_global {
|
||||
my ($name, $field) = @_;
|
||||
|
||||
my $typename = $field->getAttribute('type-name');
|
||||
my $rbname = rb_ucase($typename);
|
||||
my $offset = "'offsetof_$name'";
|
||||
|
||||
push @lines_rb, "global :$name, :$rbname, $offset";
|
||||
}
|
||||
|
||||
sub render_field_number {
|
||||
my ($name, $field) = @_;
|
||||
|
||||
my $subtype = $field->getAttribute('ld:subtype');
|
||||
my $offset = "'offsetof_$name'";
|
||||
|
||||
push @lines_rb, "number :$name, :$subtype, $offset"
|
||||
}
|
||||
|
||||
sub render_field_container {
|
||||
my ($name, $field) = @_;
|
||||
|
||||
my $subtype = $field->getAttribute('ld:subtype');
|
||||
my $offset = "'offsetof_$name'";
|
||||
|
||||
if ($subtype eq 'stl-vector') {
|
||||
my $elem = $field->findnodes('child::ld:item')->[0] or return;
|
||||
|
||||
push @lines_rb, "vector :$name, :$subtype, $offset"
|
||||
} else {
|
||||
print "no render field container $subtype\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub render_struct_fields {
|
||||
my ($type) = @_;
|
||||
|
||||
for my $field ($type->findnodes('child::ld:field')) {
|
||||
my $name = $field->getAttribute('name');
|
||||
#$name = $field->getAttribute('ld:anon-name') if (!$name);
|
||||
next if (!$name);
|
||||
my $meta = $field->getAttribute('ld:meta');
|
||||
|
||||
my $renderer = $render_struct_field{$meta};
|
||||
if ($renderer) {
|
||||
$renderer->($name, $field);
|
||||
} else {
|
||||
print "no render field $meta\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
my $input = $ARGV[0] || '../../library/include/df/codegen.out.xml';
|
||||
my $output_rb = $ARGV[1] || 'ruby-autogen.rb';
|
||||
my $output_cpp = $ARGV[2] || 'ruby-autogen.cpp';
|
||||
|
||||
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');
|
||||
|
||||
for my $name (sort { $a cmp $b } keys %global_types) {
|
||||
my $type = $global_types{$name};
|
||||
my $meta = $type->getAttribute('ld:meta');
|
||||
my $renderer = $render_global_type{$meta};
|
||||
if ($renderer) {
|
||||
$renderer->($name, $type);
|
||||
} else {
|
||||
print "no render global type $meta\n";
|
||||
}
|
||||
}
|
||||
|
||||
for my $obj ($doc->findnodes('/ld:data-definition/ld:global-object')) {
|
||||
my $name = $obj->getAttribute('name');
|
||||
}
|
||||
|
||||
open FH, ">$output_rb";
|
||||
print FH "$_\n" for @lines_rb;
|
||||
close FH;
|
||||
|
||||
open FH, ">$output_cpp";
|
||||
print FH "$_\n" for @lines_cpp;
|
||||
close FH;
|
Loading…
Reference in New Issue