package com.ochafik.lang.jnaerator;
import static com.ochafik.lang.jnaerator.parser.ElementsHelper.typeRef;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.ochafik.lang.jnaerator.parser.Declarator;
import com.ochafik.lang.jnaerator.parser.Element;
import com.ochafik.lang.jnaerator.parser.Modifier;
import com.ochafik.lang.jnaerator.parser.ModifierType;
import com.ochafik.lang.jnaerator.parser.Scanner;
import com.ochafik.lang.jnaerator.parser.TypeRef;
import com.ochafik.lang.jnaerator.parser.TypeRef.SimpleTypeRef;
import com.nativelibs4java.jalico.Pair;
public class UniversalReconciliator {
static class DefSeq {
List<SimpleTypeRef> simpleTypeRefs = new ArrayList<SimpleTypeRef>();
// List<Identifier> identifiers = new ArrayList<Identifier>();
List<Declarator> declarators = new ArrayList<Declarator>();
boolean matches(DefSeq o) {
int n = declarators.size();
if (n != declarators.size()) {
return false;
}
if (simpleTypeRefs.size() != o.simpleTypeRefs.size()) {
return false;
}
for (int i = 0; i < n; i++) {
Declarator id = declarators.get(i), oid = declarators.get(i);
if (!id.toString().equals(oid.toString())) {
return false;
}
}
return true;
}
}
DefSeq extractDefSeq(Element tr) {
final DefSeq ret = new DefSeq();
tr.accept(new Scanner() {
@Override
public void visitDeclarator(Declarator declarator) {
super.visitDeclarator(declarator);
ret.declarators.add(declarator);
}
// public void visitIdentifier(Identifier i) {
// super.visitIdentifier(i);
// ret.identifiers.add(i);
// }
@Override
public void visitSimpleTypeRef(SimpleTypeRef simpleTypeRef) {
super.visitSimpleTypeRef(simpleTypeRef);
ret.simpleTypeRefs.add(simpleTypeRef);
}
});
return ret;
}
public static class ReconciliationException extends Exception {
private static final long serialVersionUID = -8197343041734256268L;
public ReconciliationException(Element t1, Element t2, Element reason1, Element reason2) {
this(t1, t2, "\"" + reason1 + "\" and \"" + reason2 + "\" cannot be matched");
}
public ReconciliationException(Element t1, Element t2, String reason) {
super("Types \"" + t1 + "\" and \"" + t2 + "\" could not be reconciliated" + (reason == null ? "" : ". Reason = " + reason));
}
}
public Element reconciliate32bitsAnd64bits(Element tr32, Element tr64) throws ReconciliationException {
if (tr32 == null && tr64 == null) {
return null;
}
if ((tr32 == null) != (tr64 == null)) {
if (tr32 == null && tr64.toString().matches("id")
|| tr64 == null && tr32.toString().equals("id")) {
return typeRef("id");
}
throw new ReconciliationException(tr32, tr64, null);
}
tr32 = tr32.clone();
DefSeq s32 = extractDefSeq(tr32), s64 = extractDefSeq(tr64);
if (!s32.matches(s64)) {
throw new ReconciliationException(tr32, tr64, null);
}
int n = s32.simpleTypeRefs.size();
for (int i = 0; i < n; i++) {
TypeRef.SimpleTypeRef t32 = s32.simpleTypeRefs.get(i), t64 = s64.simpleTypeRefs.get(i);
if (t32.toString().equals(t64.toString())) {
continue;
}
TypeRef tr = reconciliateSimple32bitsAnd64bits(t32, t64);
if (tr == null) {
throw new ReconciliationException(tr32, tr64, t32, t64);
}
if (t32 == tr32) {
tr32 = tr;
} else {
t32.replaceBy(tr);
}
}
// TODO Auto-generated method stub
return tr32;
}
static Map<Pair<String, String>, TypeRef> predefined32_64Reconciliations = new LinkedHashMap<Pair<String, String>, TypeRef>();
static {
defRecon("float", "double", typeRef("CGFloat"));
defRecon("long", "long long", typeRef("long"));
defRecon("int", "long long", typeRef("NSInteger"));
defRecon("int", "unsigned long long", typeRef("NSInteger"));
defRecon("int", "signed long long", typeRef("NSInteger"));
defRecon("long", "unsigned long long", typeRef("NSInteger"));
defRecon("long", "signed long long", typeRef("NSInteger"));
defRecon("unsigned long", "unsigned long long", typeRef("long").addModifiers(ModifierType.Unsigned));
defRecon("unsigned int", "unsigned long long", typeRef("NSUInteger"));//int").addModifiers(ModifierType.Unsigned));
defRecon("unsigned long", "unsigned int", typeRef("int").addModifiers(ModifierType.Unsigned));
defRecon("signed long", "signed int", typeRef("int").addModifiers(ModifierType.Signed));
defRecon("long", "int", typeRef("int"));
defRecon("int", "unsigned int", typeRef("int"));
defRecon("signed long", "signed long long", typeRef("long").addModifiers(ModifierType.Signed));
defRecon("signed int", "signed long long", typeRef("NSInteger"));//int").addModifiers(ModifierType.Signed));
}
static void defRecon(String s32, String s64, TypeRef sRecon) {
predefined32_64Reconciliations.put(new Pair<String, String>(s32, s64), sRecon);
}
/*static TypeRef cleanClone(TypeRef t) {
t = t.clone();
List<Modifier> mods = new ArrayList<Modifier>(t.getModifiers());
mods.remove(ModifierType.Signed);
mods.remove(ModifierType.Unsigned);
t.setModifiers(mods);
return t;
}*/
public static TypeRef reconciliateSimple32bitsAnd64bits(TypeRef t32, TypeRef t64) {
TypeRef recon = predefined32_64Reconciliations.get(new Pair<String, String>(t32.toString(), t64.toString()));
/*if (recon == null) {
TypeRef tt32 = cleanClone(t32), tt64 = cleanClone(t64);
if (tt32.toString().equals(t64))
return tt32;
recon = predefined32_64Reconciliations.get(new Pair<String, String>(tt32.toString(), tt64.toString()));
}*/
return recon == null ? null : recon.clone();
}
}