/*
* JacORB - a free Java ORB
*
* Copyright (C) 1997-2014 Gerald Brose / The JacORB Team.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.jacorb.idl;
import java.io.File;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
/**
* @author Gerald Brose
*
*/
public class ArrayTypeSpec
extends VectorType
{
ArrayDeclarator declarator = null;
String dimensionStr = "";
public int[] dims = null;
int my_dim = 0;
private boolean written = false;
public ArrayTypeSpec(int num, TypeSpec elem,
ArrayDeclarator ad, String pack_name)
{
super(num);
declarator = ad;
name = declarator.name();
set_token(ad.get_token());
setEnclosingSymbol(ad.getEnclosingSymbol());
this.pack_name = pack_name;
type_spec = elem;
if (parser.logger.isLoggable(Level.ALL))
parser.logger.log(Level.ALL, "ArrayTypeSpec with declarator " + ad.name());
}
/**
* private constructor, only to be called from public constructor for
* multi-dimensional arrays, i.e. nested arrays. Used to create
* nested ArrayTypeSpecs
*/
private ArrayTypeSpec(int num,
TypeSpec elem,
ArrayDeclarator ad,
String pack_name,
int my_dim)
{
super(num);
declarator = ad;
name = declarator.name();
dims = declarator.dimensions();
set_token(ad.get_token());
setEnclosingSymbol(ad.getEnclosingSymbol());
this.pack_name = pack_name;
this.my_dim = my_dim;
if (dims.length > my_dim + 1)
{
type_spec =
new ArrayTypeSpec(new_num(), elem, ad, pack_name, my_dim + 1);
}
else
type_spec = elem;
// needs to be done here because nested array type specs are not parsed
StringBuffer sb = new StringBuffer();
for (int i = my_dim; i < dims.length; i++)
{
sb.append("[]");
}
dimensionStr = sb.toString();
}
/**
* clone this ArrayTypeSpec. The cloned object will not be parsed again.
*/
public Object clone()
{
ArrayTypeSpec st =
new ArrayTypeSpec(new_num(), type_spec, declarator, pack_name);
st.dims = this.dims;
st.included = this.included;
st.typedefd = this.typedefd;
st.inhibitionFlag = this.inhibitionFlag;
st.dims = dims;
st.my_dim = my_dim;
st.dimensionStr = this.dimensionStr;
st.set_token(get_token());
st.setEnclosingSymbol(getEnclosingSymbol());
return st;
}
public void setEnclosingSymbol(IdlSymbol s)
{
if (enclosing_symbol != null && enclosing_symbol != s)
throw new RuntimeException("Compiler Error: trying to reassign container for " + name);
enclosing_symbol = s;
}
public TypeSpec typeSpec()
{
return this;
}
public void setPackage(String s)
{
s = parser.pack_replace(s);
throw new RuntimeException("ArrayTypeSpec.setPackage should never be called!");
}
/**
* we have to be able to distinguish between explicitly typedef'd
* type names and anonymously defined type names
*/
public void markTypeDefd()
{
typedefd = true;
}
public void parse()
throws ParseException
{
if (parser.logger.isLoggable(Level.ALL))
parser.logger.log(Level.ALL, "ArrayTypeSpec.parse " + declarator.name());
dims = declarator.dimensions();
if (dims.length > 1)
{
type_spec =
new ArrayTypeSpec(new_num(), type_spec, declarator, pack_name, 1);
}
else if (type_spec.typeSpec() instanceof ConstrTypeSpec)
{
// locally defined, nested structs must be parsed (fixes
// bug #84) This will also result in an attempt to parse
// structs referred to through a scoped name in struct
// members, which have been inlined earlier in
// Member.java. Not a problem, structs will skip a second
// parse attempt.
type_spec.parse();
}
else if (type_spec.typeSpec() instanceof ScopedName)
{
TypeSpec ts = ((ScopedName)type_spec.typeSpec()).resolvedTypeSpec();
if (ts != null)
type_spec = ts;
}
StringBuffer sb = new StringBuffer();
for (int i = my_dim; i < dims.length; i++)
sb.append("[]");
dimensionStr = sb.toString();
try
{
if (!typedefd)
{
NameTable.define(full_name(), IDLTypes.TYPE);
// change for Prismtech JAC#572 here
//
if (!NameTable.isDefined(typeName(), IDLTypes.TYPE))
NameTable.define(typeName(), IDLTypes.TYPE);
}
}
catch (NameAlreadyDefined n)
{
parser.fatal_error("Name " + full_name() + " already defined.", null);
}
}
/**
* @return a string for an expression of type TypeCode that
* describes this type
*
* Array and sequence types always have this expression inlined in
* their containing classes because arrays and sequences can be
* locally defined (e,g, in a struct) without there being helper
* classes (so Helper.type() is not an option)
*/
public String getTypeCodeExpression()
{
return getTypeCodeExpression(new HashSet());
}
public String getTypeCodeExpression(Set knownTypes)
{
//TODO: what happens, when actual type is in knownTypes?
String originalType =
"org.omg.CORBA.ORB.init().create_array_tc(" + dims[ my_dim ] + ","
+ elementTypeSpec().getTypeCodeExpression(knownTypes) + ")";
return originalType;
}
public int getTCKind()
{
return org.omg.CORBA.TCKind._tk_array;
}
public String helperName()
{
return ScopedName.unPseudoName(full_name()) + "Helper";
}
public String holderName()
{
return ScopedName.unPseudoName(full_name()) + "Holder";
}
public String className()
{
String fullName;
if (pack_name.length() > 0)
fullName = ScopedName.unPseudoName(pack_name + "." + name);
else
fullName = ScopedName.unPseudoName(name);
String cName;
if (fullName.indexOf('.') > 0)
{
pack_name = fullName.substring(0, fullName.lastIndexOf('.'));
cName = fullName.substring(fullName.lastIndexOf('.') + 1);
}
else
{
pack_name = "";
cName = fullName;
}
return cName;
}
/**
*/
public int length()
{
return dims[ my_dim ];
}
public String printReadStatement(String var_name, String streamname)
{
if (parser.logger.isLoggable(Level.WARNING))
parser.logger.log(Level.WARNING, "Array printReadStatement");
StringBuffer sb = new StringBuffer();
String type = typeName();
sb.append(var_name + " = new " + type.substring(0, type.indexOf("[")));
sb.append("[" + length() + "]");
sb.append(type.substring(type.indexOf(']') + 1) + ";" + Environment.NL);
if (elementTypeSpec() instanceof BaseType &&
!(elementTypeSpec() instanceof AnyType))
{
String _tmp = elementTypeSpec().printReadExpression(streamname);
sb.append("\t\t" + _tmp.substring(0, _tmp.indexOf("(")) +
"_array(" + var_name + ",0," + length() + ");");
}
else
{
char idx_variable = 'i';
String indent = "";
if (var_name.endsWith("]"))
{
idx_variable = (char)(var_name.charAt(var_name.length() - 2) + 1);
indent = " ";
}
sb.append("\t\t" + indent + "for (int " + idx_variable + "=0;"
+ idx_variable + "<" + length() + ";" + idx_variable + "++)" + Environment.NL
+ "\t\t" + indent + "{" + Environment.NL);
sb.append("\t\t\t" + indent +
elementTypeSpec().printReadStatement(var_name +
"[" + idx_variable + "]", streamname) + Environment.NL);
sb.append("\t\t" + indent + "}" + Environment.NL);
}
return sb.toString();
}
public String printWriteStatement(String var_name, String streamname)
{
StringBuffer sb = new StringBuffer();
sb.append("\t\tif (" + var_name + ".length<" + length() + ")" + Environment.NL +
"\t\t\tthrow new org.omg.CORBA.MARSHAL(\"Incorrect array size \"+" +
var_name + ".length+\", expecting " + length() + "\");" + Environment.NL);
if (elementTypeSpec() instanceof BaseType &&
!(elementTypeSpec() instanceof AnyType))
{
String _tmp = elementTypeSpec().printWriteStatement(var_name, streamname);
sb.append("\t\t" + _tmp.substring(0, _tmp.indexOf("(")) +
"_array(" + var_name + ",0," + length() + ");");
}
else
{
char idx_variable = 'i';
String indent = "";
if (var_name.endsWith("]"))
{
idx_variable = (char)(var_name.charAt(var_name.length() - 2) + 1);
indent = " ";
}
sb.append("\t\t" + indent + "for (int " + idx_variable + "=0; " + idx_variable
+ "<" + length() + ";" + idx_variable + "++)" + Environment.NL
+ "\t\t" + indent + "{" + Environment.NL);
sb.append("\t\t\t" + indent + elementTypeSpec().printWriteStatement(var_name
+ "[" + idx_variable + "]", streamname)
+ Environment.NL);
sb.append("\t\t" + indent + "}" + Environment.NL);
}
return sb.toString();
}
private void printHolderClass(String className, PrintWriter ps)
{
if (!pack_name.equals(""))
ps.println("package " + pack_name + ";" + Environment.NL);
String type = typeName();
ps.println("public" + parser.getFinalString() + " class " + className + "Holder");
ps.println("\timplements org.omg.CORBA.portable.Streamable");
ps.println("{");
ps.println("\tpublic " + type + " value;");
ps.println("\tpublic " + className + "Holder ()");
ps.println("\t{");
ps.println("\t}");
ps.println("\tpublic " + className + "Holder (final " + type + " initial)" + Environment.NL + "\t{");
ps.println("\t\tvalue = initial;");
ps.println("\t}");
ps.println("\tpublic org.omg.CORBA.TypeCode _type ()");
ps.println("\t{");
ps.println("\t\treturn " + className + "Helper.type ();");
ps.println("\t}");
ps.println("\tpublic void _read (final org.omg.CORBA.portable.InputStream _in)");
ps.println("\t{");
ps.println("\t\tvalue = " + className + "Helper.read (_in);");
ps.println("\t}");
ps.println("\tpublic void _write (final org.omg.CORBA.portable.OutputStream _out)");
ps.println("\t{");
ps.println("\t\t" + className + "Helper.write (_out,value);");
ps.println("\t}");
ps.println("}");
}
private void printHelperClass(String className, PrintWriter ps)
{
if (!pack_name.equals(""))
ps.println("package " + pack_name + ";");
String type = typeName();
ps.println("public abstract class " + className + "Helper");
ps.println("{");
ps.println("\tprivate static org.omg.CORBA.TypeCode _type = " +
getTypeCodeExpression() + ";");
TypeSpec.printHelperClassMethods(ps, type);
printIdMethod(ps);
/* read */
ps.println("\tpublic static " + type +
" read (final org.omg.CORBA.portable.InputStream _in)");
ps.println("\t{");
ps.print("\t\t" + type + " result = new " +
type.substring(0, type.indexOf('[')) + "[" + length() + "]");
ps.println(type.substring(type.indexOf(']')+1) + "; // " + type);
if (elementTypeSpec() instanceof BaseType &&
!(elementTypeSpec() instanceof AnyType))
{
String _tmp = elementTypeSpec().printReadExpression("_in");
ps.println("\t\t" + _tmp.substring(0, _tmp.indexOf("(")) +
"_array(result,0," + length() + ");");
}
else
{
ps.println("\t\tfor (int i = 0; i < " + length() + "; i++)" + Environment.NL + "\t\t{");
ps.println("\t\t\t" + elementTypeSpec().printReadStatement("result[i]", "_in") + Environment.NL + "\t\t}");
}
ps.println("\t\treturn result;");
ps.println("\t}");
/* write */
ps.println("\tpublic static void write (final org.omg.CORBA.portable.OutputStream out, final " + type + " s)");
ps.println("\t{");
if (declarator.dimensions()[ 0 ] != 0)
{
ps.println("\t\tif (s.length != " + declarator.dimensions()[ 0 ] + ")");
ps.println("\t\t\tthrow new org.omg.CORBA.MARSHAL(\"Incorrect array size\");");
}
if (elementTypeSpec() instanceof BaseType &&
!(elementTypeSpec() instanceof AnyType))
{
String _tmp = elementTypeSpec().printWriteStatement("s", "out");
ps.println("\t\t" + _tmp.substring(0, _tmp.indexOf("(")) + "_array(s,0," + length() + ");");
}
else
{
ps.println("\t\tfor (int i = 0; i < s.length; i++)" + Environment.NL + "\t\t{");
ps.println("\t\t\t" + elementTypeSpec().printWriteStatement("s[i]", "out")
+ Environment.NL + "\t\t}");
}
ps.println("\t}");
ps.println("}");
}
public void print(PrintWriter _ps)
{
if (included && !generateIncluded())
return; // no code generation
try
{
// print the element type, may be a locally defined member type, e.g.
// a struct member type
type_spec.print(_ps);
// only generate class files for explicitly
// defined sequence types, i.e. for typedef'd ones
if ((!written) && typedefd)
{
// write holder file
String className = className();
String path = parser.out_dir + fileSeparator + pack_name.replace('.', fileSeparator);
File dir = new File(path);
if (!dir.exists())
{
if (!dir.mkdirs())
{
org.jacorb.idl.parser.fatal_error("Unable to create " + path, null);
}
}
String fname = className + "Holder.java";
File f = new File(dir, fname);
if (GlobalInputStream.isMoreRecentThan(f))
{
// print the mapped java class
PrintWriter ps = new PrintWriter(new java.io.FileWriter(f));
printHolderClass(className, ps);
ps.close();
}
fname = className + "Helper.java";
f = new File(dir, fname);
if (GlobalInputStream.isMoreRecentThan(f))
{
// print the mapped java class
PrintWriter ps = new PrintWriter(new java.io.FileWriter(f));
printHelperClass(className, ps);
ps.close();
}
written = true;
}
}
catch (java.io.IOException i)
{
throw new RuntimeException("File IO error" + i);
}
}
public void printInsertIntoAny(PrintWriter ps,
String anyname,
String varname)
{
String helpername = className() + "Helper";
ps.println("\t\t" + pack_name + "." + helpername + ".insert(" + anyname + ", " + varname + " );");
}
public void printExtractResult(PrintWriter ps,
String resultname,
String anyname,
String resulttype)
{
throw new RuntimeException("DII-stubs not completely implemented for array types!");
}
}