blob: 740e68154b240a5f8e38c56e57b58017a0aacc10 [file] [log] [blame]
/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.apple.internal.jobjc.generator.model.types;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import com.apple.internal.jobjc.generator.model.types.NType.NObject;
import com.apple.internal.jobjc.generator.model.types.NType.NPointer;
import com.apple.internal.jobjc.generator.model.types.NType.NPrimitive;
import com.apple.internal.jobjc.generator.model.types.NType.NVoid;
import com.apple.internal.jobjc.generator.model.types.NType.NStruct;
import com.apple.internal.jobjc.generator.model.types.NType.NField;
import com.apple.internal.jobjc.generator.utils.NTypeMerger;
import com.apple.internal.jobjc.generator.utils.QA;
import com.apple.internal.jobjc.generator.utils.Fp.Pair;
import com.apple.internal.jobjc.generator.utils.NTypeMerger.MergeFailed;
public class Type implements Comparable<Type>{
public static Type VOID = Type.getType("void", NVoid.inst(), null);
public static Type VOID_PTR = Type.getType("void*", new NPointer(NVoid.inst()), null);
final public String name;
final public NType type32;
final public NType type64;
// HACK BS bug where some types have inconsistent definitions in the metadata,
// e.g. (l / i) in some places and just (l) (and thus (l / l)) in others.
// This is a mapping from the type name to a Type object with the correct definition.
private static final Map<String, Type> exceptions;
static {
exceptions = new HashMap<String, Type>();
exceptions.put("OSStatus", getType("OSStatus", new NPrimitive('l'), new NPrimitive('i'))); // (l / i) vs. (l)
exceptions.put("CGFloat", getType("CGFloat", new NPrimitive('f'), new NPrimitive('d'))); // (f / d) vs. (f)
exceptions.put("NSRect", getType("NSRect", getNSRectType(), getCGRectType())); // ({{_NSPoint}{_NSSize}} / {{CGPoint}{CGSize}}) vs. ({{_NSPoint}{_NSSize}})
exceptions.put("NSPoint", getType("NSPoint", getNSPointType(), getCGPointType())); // (_NSPoint / CGPoint) vs. (_NSPoint)
exceptions.put("NSSize", getType("NSSize", getNSSizeType(), getCGSizeType())); // (_NSSize / CGSize) vs. (_NSSize)
exceptions.put("NSInteger", getType("NSInteger", new NPrimitive('i'), new NPrimitive('q'))); // (i / q) vs. (i)
exceptions.put("NSPointArray", getType("NSPointArray", new NPointer(getNSPointType()), new NPointer(getCGPointType()))); // (^_NSPoint / ^CGPoint) vs. (^_NSPoint)
exceptions.put("NSMultibyteGlyphPacking", getType("NSMultibyteGlyphPacking", new NPrimitive('I'), new NPrimitive('Q'))); // (I / Q) vs. (I)
exceptions.put("CFTypeRef", getType("CFTypeRef", new NPointer(NVoid.inst()), new NPointer(NVoid.inst()))); // (^v, ^v) vs. (@, @)
}
public static Type getType(final String name, final NType t32, final NType t64){
return TypeCache.inst().pingType(new Type(name, t32, t64));
}
private Type(final String name, final NType t32, final NType t64) {
QA.nonNull(t32);
this.name = cleanName(name);
this.type32 = t32;
this.type64 = t64 == null || t32.equals(t64) ? t32 : t64;
}
private JType _getJType;
public JType getJType() {
return _getJType!=null ? _getJType : (_getJType = TypeToJType.inst().getJTypeFor(TypeCache.inst().pingType(this)));
}
private String _toString;
@Override public String toString() {
return _toString != null ? _toString : (_toString = name + " " + new Pair(type32, type64).toString());
}
@Override public boolean equals(Object o){
if(o==null || !(o instanceof Type)) return false;
Type t = (Type) o;
return QA.bothNullOrEquals(t.name, this.name)
&& t.type32.equals(this.type32)
&& t.type64.equals(this.type64);
}
@Override public int hashCode(){
return (name == null ? 0 : name.hashCode())
+ type32.hashCode() + type64.hashCode();
}
public int compareTo(Type o) { return toString().compareTo(o.toString()); }
public static Type merge(Type a, Type b) throws MergeFailed{
if(a!=null && b==null) return a;
if(a==null && b!=null) return b;
if(QA.bothNullOrEquals(a, b)) return a;
if (exceptions.containsKey(a.name)) return exceptions.get(a.name); // HACK BS bug
if(a.name != null && b.name != null && !a.name.equals(b.name)){
System.out.println("Merging:");
System.out.println("\ta.....: " + a.toString());
System.out.println("\tb.....: " + b.toString());
}
final Type merged = new Type(NTypeMerger.inst().mergeName(a.name, b.name),
NTypeMerger.inst().merge(a.type32, b.type32),
NTypeMerger.inst().merge(a.type64, b.type64));
if(a.name != null && b.name != null && !a.name.equals(b.name)){
System.out.println("\tmerged: " + merged.toString());
}
return merged;
}
// HACK BS bug where sometimes the name is declared as "id <A, B..." and sometimes it's "id<A,B..."
public static String cleanName(String name){ return name == null ? null : name.replaceAll("\\s+", ""); }
// HACK BS bug where NSRect has inconsistent definitions in the metadata
// Methods return NTypes created according to the correct definitions below:
//
// {_NSRect="origin"{_NSPoint="x"f"y"f}"size"{_NSSize="width"f"height"f}} *** 32-bit
// {CGRect="origin"{CGPoint="x"d"y"d}"size"{CGSize="width"d"height"d}} *** 64-bit
private static NType getCGRectType() {
List<NField> fields = new ArrayList<NField>();
fields.add(new NField("origin", getCGPointType()));
fields.add(new NField("size", getCGSizeType()));
return new NStruct("CGRect", fields);
}
private static NType getNSRectType() {
List<NField> fields = new ArrayList<NField>();
fields.add(new NField("origin", getNSPointType()));
fields.add(new NField("size", getNSSizeType()));
return new NStruct("_NSRect", fields);
}
private static NType getCGPointType() {
List<NField> fields = new ArrayList<NField>();
fields.add(new NField("x", new NPrimitive('d')));
fields.add(new NField("y", new NPrimitive('d')));
return new NStruct("CGPoint", fields);
}
private static NType getNSPointType() {
List<NField> fields = new ArrayList<NField>();
fields.add(new NField("x", new NPrimitive('f')));
fields.add(new NField("y", new NPrimitive('f')));
return new NStruct("_NSPoint", fields);
}
private static NType getCGSizeType() {
List<NField> fields = new ArrayList<NField>();
fields.add(new NField("width", new NPrimitive('d')));
fields.add(new NField("height", new NPrimitive('d')));
return new NStruct("CGSize", fields);
}
private static NType getNSSizeType() {
List<NField> fields = new ArrayList<NField>();
fields.add(new NField("width", new NPrimitive('f')));
fields.add(new NField("height", new NPrimitive('f')));
return new NStruct("_NSSize", fields);
}
}