/*
Copyright (c) 2009-2013 Olivier Chafik, All Rights Reserved
This file is part of JNAerator (http://jnaerator.googlecode.com/).
JNAerator is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JNAerator 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with JNAerator. If not, see <http://www.gnu.org/licenses/>.
*/
package com.ochafik.lang.jnaerator;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.Set;
import com.ochafik.util.string.StringUtils;
import org.rococoa.cocoa.foundation.NSObject;
//import org.rococoa.cocoa.foundation.NSString;
import org.rococoa.Rococoa;
import org.rococoa.ObjCObject;
import static com.ochafik.lang.jnaerator.parser.ElementsHelper.*;
import com.ochafik.io.ReadText;
import com.ochafik.lang.jnaerator.parser.Arg;
import com.ochafik.lang.jnaerator.parser.Declaration;
import com.ochafik.lang.jnaerator.parser.DeclarationsHolder;
import com.ochafik.lang.jnaerator.parser.Declarator;
import com.ochafik.lang.jnaerator.parser.Enum;
import com.ochafik.lang.jnaerator.parser.Expression;
import com.ochafik.lang.jnaerator.parser.Function;
import com.ochafik.lang.jnaerator.parser.Identifier;
import com.ochafik.lang.jnaerator.parser.Modifier;
import com.ochafik.lang.jnaerator.parser.ModifierType;
import com.ochafik.lang.jnaerator.parser.Statement;
import com.ochafik.lang.jnaerator.parser.StoredDeclarations;
import com.ochafik.lang.jnaerator.parser.Struct;
import com.ochafik.lang.jnaerator.parser.TaggedTypeRefDeclaration;
import com.ochafik.lang.jnaerator.parser.TypeRef;
import com.ochafik.lang.jnaerator.parser.VariablesDeclaration;
import com.ochafik.lang.jnaerator.parser.Expression.AssignmentOp;
import com.ochafik.lang.jnaerator.parser.Expression.AssignmentOperator;
import com.ochafik.lang.jnaerator.parser.Expression.BinaryOperator;
import com.ochafik.lang.jnaerator.parser.Expression.Constant;
import com.ochafik.lang.jnaerator.parser.Expression.MemberRefStyle;
import com.ochafik.lang.jnaerator.parser.Function.SignatureType;
import com.ochafik.lang.jnaerator.parser.Statement.Block;
import com.ochafik.lang.jnaerator.parser.StoredDeclarations.TypeDef;
import com.ochafik.lang.jnaerator.parser.Struct.Type;
import com.ochafik.lang.jnaerator.parser.TypeRef.FunctionSignature;
import com.ochafik.lang.jnaerator.parser.TypeRef.SimpleTypeRef;
import com.ochafik.lang.jnaerator.parser.TypeRef.TaggedTypeRef;
import java.util.*;
import org.rococoa.ObjCClass;
import org.rococoa.cocoa.foundation.NSClass;
/*
include com/ochafik/lang/jnaerator/ObjectiveCStaticForwardsExcludeList.data
include com/ochafik/lang/jnaerator/ObjectiveCProtocolsForcedInheritanceList.data
*/
public class ObjectiveCGenerator {
String classClassName = "_class_",
classInterfaceNameInCategoriesAndProtocols = "_static_",
classInstanceName = "_NSCLASS_",
classInstanceGetterName = "getNSClass";
boolean AUTO_RELEASE_IN_FACTORIES = false;
static Map<String, Set<String>> protocolsForcedInheritance;
public static Set<String> getForcedProtocolParents(String protocolName) {
if (protocolsForcedInheritance == null) {
protocolsForcedInheritance = new LinkedHashMap<String, Set<String>>();
try {
InputStream in = ObjectiveCGenerator.class.getClassLoader().getResourceAsStream("com/ochafik/lang/jnaerator/ObjectiveCProtocolsForcedInheritanceList.data");
List<String> lines = ReadText.readLines(in);
for (String line : lines) {
line = line.trim();
if (line.startsWith("//") || line.startsWith("#") || line.length() == 0) {
continue;
}
String[] tks = line.split(":");
protocolsForcedInheritance.put(tks[0], new TreeSet<String>(Arrays.asList(tks[1].split(","))));
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
Set<String> ret = protocolsForcedInheritance.get(protocolName);
return ret == null ? Collections.EMPTY_SET : ret;
}
static Map<String, Set<String>> methodsExcludedFromStaticForwarding;
public static boolean isMethodExcludedFromStaticForwarding(Function m) {
if (methodsExcludedFromStaticForwarding == null) {
methodsExcludedFromStaticForwarding = new LinkedHashMap<String, Set<String>>();
try {
InputStream in = ObjectiveCGenerator.class.getClassLoader().getResourceAsStream("com/ochafik/lang/jnaerator/ObjectiveCStaticForwardsExcludeList.data");
// InputStream in = new FileInputStream("/Users/ochafik/Prog/Java/sources/com/ochafik/lang/jnaerator/ObjectiveCStaticForwardsExcludeList.data");
List<String> lines = ReadText.readLines(in);
for (String line : lines) {
line = line.trim();
if (line.startsWith("//") || line.startsWith("#") || line.length() == 0) {
continue;
}
String[] tks = line.split("\\|");
String className = tks[0].trim(), methodSignature = tks[1].trim();
Set<String> set = methodsExcludedFromStaticForwarding.get(className);
if (set == null) {
methodsExcludedFromStaticForwarding.put(className, set = new HashSet<String>());
}
set.add(methodSignature);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
if (!(m.getParentElement() instanceof Struct)) {
return false;
}
Struct s = (Struct) m.getParentElement();
Identifier n = s.getTag();
if (n != null && n.equals("NSObject"))// || n.equals("NSClass"))
{
return true;
}
String sig = m.computeSignature(SignatureType.JavaStyle);
if (DeclarationsConverter.getMethodsAndTheirSignatures(NSObject.class).getSecond().contains(sig)) {
return true;
}
String cn = s.getTag() == null ? "" : s.getTag().toString();
Set<String> set = methodsExcludedFromStaticForwarding.get(cn);
if (set != null && set.contains(sig)) {
return true;
}
set = methodsExcludedFromStaticForwarding.get("");
if (set != null && set.contains(sig)) {
return true;
}
return false;
}
public ObjectiveCGenerator(Result result) {
this.result = result;
}
final Result result;
public Struct getStruct(Identifier className, Struct.Type type) {
return Result.getMap(result.classes, type).get(className);
}
public Identifier getPackageName(Struct struct) {
if (struct == null) {
return null;
}
String library = result.getLibrary(struct);
Identifier javaPackage = result.getLibraryPackage(library);
//if (struct.getType() == Struct.Type.ObjCClass) {
// String name = String.valueOf(struct.getTag());
//if (name.equals("NSObject"))
// javaPackage = ident(NSObject.class.getPackage().getName().split("\\."));
//else if (name.equals("NSClass"))
// javaPackage = ident(NSClass.class.getPackage().getName().split("\\."));
//else if (name.equals("NSString"))
// javaPackage = ident(NSString.class.getPackage().getName().split("\\."));
//}
if (struct.getType() == Type.ObjCProtocol) {
javaPackage = ident(javaPackage, "protocols");
} else if (struct.getCategoryName() != null) {
javaPackage = ident(javaPackage, "categories");
}
return javaPackage;
}
public Identifier getFullClassName(Struct struct) {
if (struct == null) {
return null;
}
Identifier javaPackage = getPackageName(struct);
Identifier tag = struct.getTag();
String categ = struct.getCategoryName();
Identifier fullName = ident(javaPackage, categ == null ? tag.clone() : ident(categ));
return fullName;
}
public void generateObjectiveCClasses() throws IOException {
for (Struct in : Result.getMap(result.classes, Type.ObjCClass).values()) {
outputObjectiveCClass(in);
}
for (Struct protocol : Result.getMap(result.classes, Type.ObjCProtocol).values()) {
for (String parent : getForcedProtocolParents(String.valueOf(protocol.getTag()))) {
protocol.addParent(ident(parent));
}
outputObjectiveCClass(protocol);
}
}
public void outputObjectiveCClass(Struct in) throws IOException {
Identifier fullClassName = getFullClassName(in);
Signatures signatures = new Signatures();
Struct s = generateObjectiveCClass(in, signatures);
result.notifyBeforeWritingClass(fullClassName, s, signatures, result.getLibrary(in));
PrintWriter out = result.classOutputter.getClassSourceWriter(fullClassName.toString());
result.printJavaClass(getPackageName(in), s, out);
out.close();
}
static Identifier NSObjectIdent = ident(NSObject.class),
ObjCObjectIdent = ident(ObjCObject.class),
ObjCClassIdent = ident(ObjCClass.class);
//NSClassIdent = ident(NSClass.class);
public Struct generateObjectiveCClass(Struct in, Signatures signatures) throws IOException {
boolean isProtocol = in.getType() == Type.ObjCProtocol, isCategory = in.getCategoryName() != null;
Struct instanceStruct = new Struct().addModifiers(ModifierType.Public);
instanceStruct.setCommentBefore(in.getCommentBefore());
instanceStruct.addToCommentBefore(in.getCommentAfter());
instanceStruct.setTag(isCategory ? ident(in.getCategoryName()) : in.getTag().clone());
if (isProtocol || isCategory) {
instanceStruct.setType(Type.JavaInterface);
} else {
instanceStruct.addModifiers(ModifierType.Abstract).setType(Type.JavaClass);
}
Struct classStruct = new Struct();
classStruct.setTag(ident(classClassName));
classStruct.setType(Struct.Type.JavaClass);
classStruct.addModifiers(ModifierType.Public, ModifierType.Static, ModifierType.Abstract);
List<SimpleTypeRef> interfacesForInstance = new ArrayList<SimpleTypeRef>();
List<SimpleTypeRef> parentsForInstance = new ArrayList<SimpleTypeRef>(in.getParents());
//for (Identifier p : parentsForInstance)
// parentsForClass
boolean isNSObject = in.getTag().equals(NSObject.class.getSimpleName());
/*if (parentsForInstance.isEmpty()) {
if (isProtocol || isCategory)
parentsForInstance.add(ObjCObjectIdent);
else
if (!isNSObject)
parentsForInstance.add(NSObjectIdent);
}*/
//interfacesForClass.add(ObjCClassIdent);
if (!(isCategory || isProtocol)) {
for (Struct catIn : Result.getMap(result.objCCategoriesByTargetType, in.getTag()).values()) {
Identifier catId = getFullClassName(catIn);
Identifier sim = catId.resolveLastSimpleIdentifier();
String categName = catIn.getTag() + "_" + sim;
if (add(instanceStruct, createCastMethod(ident(categName), catId, false), signatures)) {
classStruct.addDeclaration(createCastMethod(ident(categName), ident(catId, classInterfaceNameInCategoriesAndProtocols), true));
}
//interfacesForInstance.add(catId);
//interfacesForClass.add(ident(catId, classInterfaceNameInCategoriesAndProtocols));
outputObjectiveCClass(catIn);
}
}
for (SimpleTypeRef sp : parentsForInstance) {
Identifier p = sp.getName();
String ps = p.toString();
boolean basic = ps.toString().equals(ObjCObject.class.getName()) || ps.equals(NSObject.class.getName());
Identifier id = basic ? p : result.typeConverter.findObjCClassIdent(p);
//Identifier id = result.typeConverter.findObjCClassIdent(p);
if (id != null || (!p.isPlain() && (id = p) != null)) {
if (ps.toString().equals("NSObject")) {
instanceStruct.addProtocol(ident(ObjCObject.class));
} else {
instanceStruct.addParent(id.clone());
}
if (!basic) {
classStruct.addParent(ident(id, classClassName));
}
}
}
/*for (Identifier p : interfacesForClass) {
boolean basic = p == ObjCClassIdent || p == NSObjectIdent;
Identifier id = basic ? p : result.typeConverter.findObjCClassIdent(p);
if (id != null)
classStruct.addProtocol(p);
}*/
boolean isInterface = isProtocol || isCategory;
if (instanceStruct.getParents().isEmpty()) {
if (isInterface) {
instanceStruct.addParent(ident(ObjCObject.class));
} else if (isNSObject) {
instanceStruct.addProtocol(ident(ObjCObject.class));
} else {
instanceStruct.addParent(ident(NSObject.class));
}
}
if (classStruct.getParents().isEmpty()) {
if (isNSObject) {
classStruct.addParent(ident(NSClass.class));
} else {
classStruct.addParent(ident(ident(NSObject.class), classClassName));
}
//classStruct.addProtocol(ident(ObjCClass.class));
}
for (SimpleTypeRef p : in.getProtocols()) {
Identifier id = getFullClassName(getStruct(p.getName(), Type.ObjCProtocol));
if (id != null) {
interfacesForInstance.add(typeRef(id));
}
}
for (SimpleTypeRef id : interfacesForInstance) {
if (isProtocol || isCategory) {
instanceStruct.addParent(id);
} else {
instanceStruct.addProtocol(id);
}
}
// CompoundCollection<Declaration> declarations = new CompoundCollection<Declaration>();
// declarations.addComponent(in.getDeclarations());
// for (Struct catIn : Result.getMap(result.objCCategoriesByTargetType, in.getTag()).values()) {
// for (Declaration d : catIn.getDeclarations())
// d.addToCommentBefore("From category " + catIn.getCategoryName());
// declarations.addComponent(catIn.getDeclarations());
//
// if (catIn.getCommentBefore() != null)
// instanceStruct.addToCommentBefore("<p>Category " + catIn.getTag()+ " : " + catIn.getCommentBefore() +"</p>");
// }
StoredDeclarations classHolder = new VariablesDeclaration();
if (!(isProtocol || isCategory)) {
classHolder.addModifiers(ModifierType.Private, ModifierType.Static);
}
classHolder.setValueType(typeRef(classClassName));
Expression.FunctionCall call = methodCall(expr(typeRef(Rococoa.class)), MemberRefStyle.Dot, "createClass");
call.addArgument(expr(in.getTag().toString()));
call.addArgument(memberRef(expr(typeRef(classClassName)), MemberRefStyle.Dot, "class"));
Function classGetter;
if (isProtocol || isCategory) {
classGetter = null;
classHolder.addDeclarator(new Declarator.DirectDeclarator(classInstanceName, call));
} else {
classHolder.addDeclarator(new Declarator.DirectDeclarator(classInstanceName));
classGetter = new Function(Function.Type.JavaMethod, ident(classInstanceGetterName), typeRef(classClassName));
classGetter.addModifiers(ModifierType.Public, ModifierType.Static);
classGetter.setBody(new Block(
new Statement.If(
expr(
varRef(classInstanceName),
BinaryOperator.IsEqual,
Constant.newNull()),
new Statement.ExpressionStatement(
new AssignmentOp(
varRef(classInstanceName),
AssignmentOperator.Equal,
call)),
null),
new Statement.Return(varRef(classInstanceName))));
}
Struct classInterfaceStruct = null, structThatReceivesStaticMethods;
if (isProtocol || isCategory) {
structThatReceivesStaticMethods = classInterfaceStruct = new Struct();
classInterfaceStruct.setType(Struct.Type.JavaInterface);
classInterfaceStruct.setTag(ident(classInterfaceNameInCategoriesAndProtocols));
classInterfaceStruct.addParent(ident(ObjCClass.class));
classStruct.addProtocol(ident(classInterfaceNameInCategoriesAndProtocols));
} else {
structThatReceivesStaticMethods = classStruct;
}
if (!(isProtocol || isCategory)) {
addAllocIfMissing(in, "alloc");
addAllocIfMissing(in, "new_");
}
Identifier fullClassName = getFullClassName(in);
outputMembers(signatures, in, instanceStruct, structThatReceivesStaticMethods, in.getDeclarations(), isProtocol || isCategory);
/*
if (!isProtocol && !isCategory) {
// Output static proxies for static category methods
for (Struct catIn : Result.getMap(result.objCCategoriesByTargetType, in.getTag()).values()) {
for (Declaration d : catIn.getDeclarations()) {
if (!(d instanceof Function))
continue;
Function f = (Function)d;
if (!f.hasModifier(ModifierType.Static))
continue;
List<Declaration> decls = new ArrayList<Declaration>();
result.declarationsConverter.convertFunction(f, null, false, new DeclarationsHolder.ListWrapper(decls), fullClassName);
if (f.getModifiers().contains(ModifierType.Static)) {
for (Declaration decl : decls) {
if (!(decl instanceof Function))
continue;
Function pf = (Function)decl;
if (!signatures.methodsSignatures.add(pf.computeSignature(false)))
continue;
//if (!add(classStruct, decl, signatures, objSigs, clasSigs))
// continue;
instanceStruct.addDeclaration(createProxyCopy(pf, (Function)decl));
}
}
}
}
}*/
instanceStruct.addDeclaration(decl(classInterfaceStruct));
if (!isCategory) {// && !structThatReceivesStaticMethods.getDeclarations().isEmpty()) {
instanceStruct.addDeclaration(new TaggedTypeRefDeclaration(classStruct));
instanceStruct.addDeclaration(classGetter);
instanceStruct.addDeclaration(classHolder);
}
return instanceStruct;
}
Function createCastMethod(Identifier name, Identifier classId, boolean isStatic) {
Function m = new Function();
m.setType(Function.Type.JavaMethod);
m.addModifiers(ModifierType.Public);
m.setName(ident("as" + (isStatic ? "Static_" : "_") + name));
m.setValueType(typeRef(classId.clone()));
m.setBody(block(
new Statement.Return(
methodCall(
expr(typeRef(Rococoa.class)),
MemberRefStyle.Dot,
"cast",
varRef("this"),
result.typeConverter.typeLiteral(typeRef(classId.clone()))))));
return m;
}
private void addAllocIfMissing(Struct in, String allocName) {
Identifier n = in.getTag();
if (n.equals("NSObject") || n.equals("NSClass")) {
return;
}
boolean hasAlloc = false;
for (Declaration d : in.getDeclarations()) {
if (d instanceof Function) {
Function f = (Function) d;
if (f.getArgs().isEmpty() && allocName.equals(f.getName())) {
hasAlloc = true;
break;
}
}
}
if (!hasAlloc) {
in.addDeclaration(new Function(Function.Type.ObjCMethod, ident(allocName), typeRef(in.getTag())).addModifiers(ModifierType.Static));
}
}
private void outputMembers(Signatures signatures, Struct in, Struct instanceStruct,
Struct classStruct, List<Declaration> declarations, boolean isProtocol) throws IOException {
Identifier fullClassName = getFullClassName(in);
instanceStruct.setResolvedJavaIdentifier(fullClassName);
Set<String> objSigs = DeclarationsConverter.getMethodsAndTheirSignatures(NSObject.class).getSecond(),
clasSigs = new HashSet<String>();//DeclarationsConverter.getMethodsAndTheirSignatures(NSClass.class).getSecond();
int[] iChild = new int[1];
for (Declaration d : declarations) {
if (d instanceof Function) {
Function f = (Function) d;
List<Declaration> decls = new ArrayList<Declaration>();
DeclarationsHolder out = new DeclarationsHolder.ListWrapper(decls);
result.declarationsConverter.convertFunction(f, null/*signatures*/, false, out, out, fullClassName, -1);
if (f.hasModifier(ModifierType.Static)) {
for (Declaration decl : decls) {
if (!add(classStruct, decl, signatures, objSigs, clasSigs)) {
continue;
}
if (!isProtocol && decl instanceof Function) {
instanceStruct.addDeclaration(createProxyCopy(f, (Function) decl));
signatures.addMethod((Function) decl);
}
if (classStruct.getType() == Type.JavaClass) {
decl.addModifiers(ModifierType.Public, ModifierType.Abstract);
decl.reorganizeModifiers();
}
}
} else {
for (Declaration decl : decls) {
if (!add(instanceStruct, decl, signatures, objSigs)) {
continue;
}
if (!isProtocol && decl instanceof Function) {
//
Function addedF = createCreateCopyFromInit((Function) decl, instanceStruct);
signatures.addMethod((Function) decl);
instanceStruct.addDeclaration(addedF);
if (instanceStruct.getType() == Type.JavaClass) {
decl.addModifiers(ModifierType.Public, ModifierType.Abstract);
decl.reorganizeModifiers();
}
}
}
}
// } else if (d instanceof VariablesDeclaration) {
// result.declarationsConverter.convertVariablesDeclaration((VariablesDeclaration)d, instanceStruct, iChild, fullClassName);
} else if (d instanceof TaggedTypeRefDeclaration) {
TaggedTypeRef tr = ((TaggedTypeRefDeclaration) d).getTaggedTypeRef();
if (tr instanceof Struct) {
result.declarationsConverter.outputConvertedStruct((Struct) tr, signatures, instanceStruct, null, false);
} else if (tr instanceof Enum) {
result.declarationsConverter.convertEnum((Enum) tr, signatures, instanceStruct, fullClassName);
}
} else if (d instanceof TypeDef) {
TypeDef td = (TypeDef) d;
TypeRef tr = td.getValueType();
if (tr instanceof Struct) {
result.declarationsConverter.outputConvertedStruct((Struct) tr, signatures, instanceStruct, null, false);
} else if (tr instanceof FunctionSignature) {
result.declarationsConverter.convertCallback((FunctionSignature) tr, signatures, instanceStruct, fullClassName);
}
}
iChild[0]++;
}
}
private boolean add(Struct classStruct, Declaration decl, Signatures signatures, Set<?>... additionalMethodSignatures) {
if (decl instanceof Function) {
String sig = ((Function) decl).computeSignature(SignatureType.JavaStyle);
for (Set<?> sigs : additionalMethodSignatures) {
if (sigs.contains(sig)) {
return false;
}
}
if (signatures.addMethod(sig)) {
classStruct.addDeclaration(decl);
return true;
} else {
return false;
}
}
classStruct.addDeclaration(decl);
return true;
}
/**
* Create a createXXXWithYYY factory
*
* @param meth
* @param instanceStruct
* @return
*/
private Function createCreateCopyFromInit(Function meth, TaggedTypeRef instanceStruct) {
String name = meth.getName().toString();
if (!name.matches("^init([A-Z].*|)$")) {
return null;
}
//if (name.startsWith("init") && (name.equals("init") || !Character.isUpperCase(name.charAt("init".length()))))
Function createCopy = meth.clone();
createCopy.setCommentBefore("Factory method");
createCopy.addToCommentBefore("@see #" + meth.computeSignature(SignatureType.JavaStyle));
createCopy.setName(ident("create" + name.substring("init".length())));
createCopy.addModifiers(ModifierType.Public, ModifierType.Static);
createCopy.reorganizeModifiers();
Expression[] args = new Expression[meth.getArgs().size()];
int i = 0;
for (Arg arg : meth.getArgs()) {
args[i++] = varRef(arg.getName());
}
Expression val = methodCall(
methodCall(
methodCall(null, null, classInstanceGetterName),
Expression.MemberRefStyle.Dot,
"alloc"),
Expression.MemberRefStyle.Dot,
meth.getName().toString(),
args);
if (AUTO_RELEASE_IN_FACTORIES) {
val = methodCall(val, MemberRefStyle.Dot, "autorelease");
val =
methodCall(expr(typeRef(Rococoa.class)), MemberRefStyle.Dot, "cast",
val,
memberRef(expr(typeRef(instanceStruct.getTag())), MemberRefStyle.Dot, "class"));
}
createCopy.setBody(new Block(new Statement.Return(val)));
return createCopy;
}
private Function createProxyCopy(Function originalMethod, Function meth) {
if (isMethodExcludedFromStaticForwarding(originalMethod)) {
return null;
}
Function proxyCopy = meth.clone();
proxyCopy.addModifiers(ModifierType.Public, ModifierType.Static);
proxyCopy.reorganizeModifiers();
Expression[] args = new Expression[meth.getArgs().size()];
int i = 0;
for (Arg arg : meth.getArgs()) {
args[i++] = varRef(arg.getName());
}
Expression val = methodCall(methodCall(null, null, classInstanceGetterName), Expression.MemberRefStyle.Dot, meth.getName().toString(), args);
proxyCopy.setBody(new Block(
meth.getValueType() == null || "void".equals(meth.getValueType().toString()) ? stat(val) : new Statement.Return(val)));
return proxyCopy;
}
// protected static _class_ _CLASS_ = org.rococoa.Rococoa.createClass("NSURL", _class_.class);
// public abstract class _class_ extends
// org.rococoa.NSClass {
// //org.rococoa.NSObject._class_ {
// }
}