/usr/local/CPAN/CORBA-XPIDL/CORBA/XPIDL/JavaVisitor.pm
package CORBA::XPIDL::JavaVisitor;
use strict;
use warnings;
our $VERSION = '0.20';
use File::Basename;
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
bless $self, $class;
my ($parser) = @_;
$self->{srcname} = $parser->YYData->{srcname};
$self->{symbtab} = $parser->YYData->{symbtab};
my $filename;
if ($parser->YYData->{opt_e}) {
$filename = $parser->YYData->{opt_e};
}
else {
if ($parser->YYData->{opt_o}) {
$filename = $parser->YYData->{opt_o} . '.java';
}
else {
$filename = basename($self->{srcname}, '.idl') . '.java';
}
}
$self->open_stream($filename);
$self->{num_key} = 'num_doc_xp';
return $self;
}
sub open_stream {
my $self = shift;
my ($filename) = @_;
open $self->{out}, '>', $filename
or die "can't open $filename ($!).\n";
$self->{filename} = $filename;
}
sub _get_defn {
my $self = shift;
my ($defn) = @_;
if (ref $defn) {
return $defn;
}
else {
return $self->{symbtab}->Lookup($defn);
}
}
sub _classname_iid {
my $self = shift;
my ($node) = @_;
my $idf = $node->{idf};
$idf =~ s/^ns/NS_/; # backcompat naming styles
my $classname = uc $idf;
$classname .= '_IID';
return $classname;
}
sub _comment {
my $self = shift;
my ($node) = @_;
return q{} unless ($node->{doc});
my $FH = $self->{out};
my $indent = q{ } x 4;
print $FH $indent,"/**\n";
foreach (split /\n/, $node->{doc}) {
s/^\s+//;
next unless ($_);
print $FH $indent," * ",$_,"\n";
}
print $FH $indent," */\n";
}
sub _java_type {
my $self = shift;
my ($node) = @_;
while ($node->isa('TypeDeclarator')) {
$node = $self->_get_defn($node->{type});
}
if ($node->isa('VoidType')) {
return 'Object';
}
elsif ($node->isa('IntegerType')) {
if ($node->{value} eq 'short') {
return 'short';
}
elsif ($node->{value} eq 'unsigned short') {
return 'short';
}
elsif ($node->{value} eq 'long') {
return 'int';
}
elsif ($node->{value} eq 'unsigned long') {
return 'int';
}
elsif ($node->{value} eq 'long long') {
return 'long';
}
elsif ($node->{value} eq 'unsigned long long') {
return 'long';
}
else {
warn __PACKAGE__,"::_java_type (IntegerType) $node->{value}.\n";
}
}
elsif ($node->isa('CharType')) {
return 'char';
}
elsif ($node->isa('WideCharType')) {
return 'char';
}
elsif ($node->isa('StringType')) {
return 'String';
}
elsif ($node->isa('WideStringType')) {
return 'String';
}
elsif ($node->isa('BooleanType')) {
return 'boolean';
}
elsif ($node->isa('OctetType')) {
return 'byte';
}
elsif ($node->isa('FloatingPtType')) {
if ($node->{value} eq 'float') {
return 'float';
}
elsif ($node->{value} eq 'double') {
return 'double';
}
elsif ($node->{value} eq 'long double') {
warn __PACKAGE__," 'long double' not available at this time for Java.\n";
return 'double';
}
else {
warn __PACKAGE__,"::_java_type (FloatingType) $node->{value}.\n";
}
}
elsif ($node->isa('NativeType')) {
if ( $node->{native} eq 'void' ) {
return 'Object';
}
elsif ( $node->{native} eq 'nsID'
or $node->{native} eq 'nsIID'
or $node->{native} eq 'nsCID' ) {
# XXX: s.b test for "iid" attribute
# XXX: special class for nsIDs
return 'nsID';
}
else {
# XXX: special class for opaque types
return 'OpaqueValue';
}
}
elsif ($node->isa('BaseInterface')) {
return $node->{idf};
}
elsif ($node->isa('ForwardBaseInterface')) {
return $node->{idf};
}
else {
my $class = ref $node;
warn __PACKAGE__,"::_java_type unknown type ($class).\n";
}
}
#
# 3.5 OMG IDL Specification
#
sub visitSpecification {
my $self = shift;
my ($node) = @_;
my $FH = $self->{out};
print $FH "/*\n";
print $FH " * ************* DO NOT EDIT THIS FILE ***********\n";
print $FH " *\n";
print $FH " * This file was automatically generated from ",$self->{srcname},".\n";
print $FH " */\n";
print $FH "\n";
foreach (@{$node->{list_decl}}) {
$self->_get_defn($_)->visit($self);
}
print $FH "\n";
print $FH "/*\n";
print $FH " * end\n";
print $FH " */\n";
close $FH;
}
#
# 3.6 Import Declaration
#
sub visitImport {
# empty
}
#
# 3.7 Module Declaration
#
sub visitModules {
my $self = shift;
my ($node) = @_;
unless (exists $node->{$self->{num_key}}) {
$node->{$self->{num_key}} = 0;
}
my $module = ${$node->{list_decl}}[$node->{$self->{num_key}}];
$module->visit($self);
$node->{$self->{num_key}} ++;
}
sub visitModule {
my $self = shift;
my ($node) = @_;
foreach (@{$node->{list_decl}}) {
$self->_get_defn($_)->visit($self);
}
}
#
# 3.8 Interface Declaration
#
sub visitBaseInterface {
# empty
}
sub visitRegularInterface {
my $self = shift;
my ($node) = @_;
return unless ($self->{srcname} eq $node->{filename});
my $FH = $self->{out};
# Write out JavaDoc comment
print $FH "\n";
print $FH "/**\n";
print $FH " * Interface ",$node->{idf},"\n";
my $iid = $node->getProperty('uuid');
if (defined $iid) {
print $FH " *\n";
print $FH " * IID: 0x",$iid,"\n";
}
print $FH " */\n";
print $FH "\n";
# Write "public interface <foo>"
print $FH "public interface ",$node->{idf};
if (exists $node->{inheritance}) {
print $FH " extends ";
my $first = 1;
foreach (@{$node->{inheritance}->{list_interface}}) {
my $base = $self->_get_defn($_);
print $FH ", " unless ($first);
print $FH $base->{idf};
$first = 0;
}
}
print $FH "\n";
print $FH "{\n";
if (defined $iid) {
my $classname_iid = $self->_classname_iid($node);
# Write interface constants for IID
print $FH " public static final String ",$classname_iid,"_STRING =\n";
print $FH " \"",$iid,"\";\n";
print $FH "\n";
print $FH " public static final nsID ",$classname_iid," =\n";
print $FH " new nsID(\"",$iid,"\");\n";
print $FH "\n";
}
foreach (@{$node->{list_decl}}) {
$self->_get_defn($_)->visit($self);
}
print $FH "}\n";
print $FH "\n";
}
sub visitForwardBaseInterface {
# empty
}
#
# 3.10 Constant Declaration
#
sub visitConstant {
my $self = shift;
my ($node) = @_;
my $FH = $self->{out};
my $type = $self->_get_defn($node->{type});
my $java_type = $self->_java_type($type);
my $value = $node->{value}->{value};
print $FH "\n";
$self->_comment($node);
print $FH " public static final ",$java_type," ",$node->{idf}," = ",$value,";\n";
}
sub visitExpression {
# empty
}
#
# 3.11 Type Declaration
#
sub visitTypeDeclarators {
# empty
}
sub visitNativeType {
# empty
}
#
# 3.11.2 Constructed Types
#
sub visitStructType {
# empty
}
sub visitUnionType {
# empty
}
sub visitForwardStructType {
# empty
}
sub visitForwardUnionType {
# empty
}
# 3.11.2.4 Enumerations
#
sub visitEnumType {
# empty
}
#
# 3.12 Exception Declaration
#
sub visitException {
# empty
}
#
# 3.13 Operation Declaration
#
sub visitOperation {
my $self = shift;
my ($node) = @_;
my $FH = $self->{out};
my $method_notxpcom = $node->hasProperty('notxpcom');
my $method_noscript = $node->hasProperty('noscript');
print $FH "\n";
$self->_comment($node);
# Write beginning of method declaration
print $FH " ";
# Nonscriptable methods become package-protected
print $FH "public " unless ($method_noscript);
# Write return type
# Unlike C++ headers, Java interfaces return the declared
# return value; an exception indicates XPCOM method failure.
my $type = $self->_get_defn($node->{type});
if ($method_notxpcom or !$type->isa('VoidType')) {
print $FH $self->_java_type($type);
}
else {
# Check for retval attribute
my $retval_param;
foreach (@{$node->{list_param}}) {
if ($_->hasProperty('retval')) {
$retval_param = $_;
last;
}
}
if (defined $retval_param) {
$type = $self->_get_defn($retval_param->{type});
print $FH $self->_java_type($type);
}
else {
print $FH "void";
}
}
# Write method name
print $FH " ",lcfirst($node->{idf}),"(";
# Write parameters
my $first = 1;
foreach (@{$node->{list_param}}) {
# Skip "retval"
next if ($_->hasProperty('retval'));
print $FH ", " unless ($first);
# Put in type of parameter
$type = $self->_get_defn($_->{type});
print $FH $self->_java_type($type);
# If the parameter is out or inout, make it a Java array of the
# appropriate type
print $FH "[]" if ($_->{attr} ne "in");
#Put in name of parameter
print $FH " ",$_->{idf};
$first = 0;
}
print $FH ")";
if (exists $node->{list_raise}) {
print $FH " throws ";
$first = 1;
foreach (@{$node->{list_raise}}) { # exception
my $defn = $self->_get_defn($_);
print $FH ", " unless ($first);
print $FH $defn->{idf};
$first = 0;
}
}
print $FH ";\n";
}
#
# 3.14 Attribute Declaration
#
sub visitAttributes {
my $self = shift;
my ($node) = @_;
foreach (@{$node->{list_decl}}) {
$self->_get_defn($_)->visit($self);
}
}
sub visitAttribute {
my $self = shift;
my ($node) = @_;
my $FH = $self->{out};
my $method_noscript = $node->hasProperty('noscript');
my $type = $self->_get_defn($node->{type});
print $FH "\n";
$self->_comment($node);
# Write access permission ("public" unless nonscriptable)
print $FH " ";
print $FH "public " unless ($method_noscript);
# Write the proper Java return value for the get operation
print $FH $self->_java_type($type);
# Write the name of the accessor ("get") method.
print $FH " get",ucfirst($node->{idf}),"();\n";
unless (exists $node->{modifier}) { # readonly
# Nonscriptable methods become package-protected
print $FH " ";
print $FH "public " unless ($method_noscript);
# Write attribute access method name and return type
print $FH "void set",ucfirst($node->{idf}),"(";
# Write the proper Java type for the set operation
print $FH $self->_java_type($type);
# Write the name of the formal parameter.
print $FH " value);\n"
}
}
#
# 3.15 Repository Identity Related Declarations
#
sub visitTypeId {
# empty
}
sub visitTypePrefix {
# empty
}
#
# XPIDL
#
sub visitCodeFragment {
# empty
}
1;