/*
* 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;
import java.util.Arrays;
import org.w3c.dom.Node;
import com.apple.internal.jobjc.generator.model.types.Type;
import com.apple.internal.jobjc.generator.model.types.JType.JPrimitive;
import com.apple.internal.jobjc.generator.model.types.NType.NPrimitive;
import com.apple.internal.jobjc.generator.utils.Fp;
import com.apple.jobjc.JObjCRuntime;
public class NativeEnum extends ElementWType<Framework> {
public final String value, value64, le_value, be_value;
public boolean ignore;
public String suggestion;
public NativeEnum(final Node node, final Framework parent) {
super(node, typeForEnum(getAttr(node, "name"),
getAttr(node, "value"), getAttr(node, "value64"),
getAttr(node, "le_value"), getAttr(node, "be_value"),
getAttr(node, "ignore")), parent);
this.value = getAttr(node, "value");
this.value64 = getAttr(node, "value64");
this.le_value = getAttr(node, "le_value");
this.be_value = getAttr(node, "be_value");
String ignoreS = getAttr(node, "ignore");
this.ignore = ignoreS == null ? false : Boolean.parseBoolean(ignoreS);
this.suggestion = getAttr(node, "suggestion");
assert valueToString() != null;
}
private static Type typeForEnum(String name, String value32, String value64, String le_value, String be_value, String ignore){
if("true".equals(ignore)) return Type.getType(null, NPrimitive.inst('i'), null);
NumTest[] tests = new NumTest[]{new IntTest(), new LongTest(), new FloatTest(), new DoubleTest()};
for(NumTest t : tests)
if(t.confirm(value32, value64, le_value, be_value))
return t.getType();
throw new NumberFormatException(String.format("Failed to parse type for enum: %1$s = 32: %2$s / 64: %3$s / le: %4$s / be: %5$s\n",
name, value32, value64, le_value, be_value));
}
public String valueToString(){
if(ignore == true) return "0";
JPrimitive jprim = (JPrimitive) type.getJType();
if(le_value == null && be_value == null){
if(value == null && value64 != null)
return value64 + jprim.getLiteralSuffix();
else if(value != null && value64 == null)
return value + jprim.getLiteralSuffix();
else
return String.format("(%1$s.IS64 ? %2$s%4$s : %3$s%4$s)", JObjCRuntime.class.getName(),
value64, value, jprim.getLiteralSuffix());
}
else if(value == null && value64 == null){
return String.format("(%1$s.IS_BIG_ENDIAN ? %2$s%4$s : %3$s%4$s)",
JObjCRuntime.class.getName(), be_value, le_value, jprim.getLiteralSuffix());
}
throw new RuntimeException("Unable to produce a value for enum " + name);
}
// Used to find the best type to use for the enum.
static abstract class NumTest{
public boolean confirm(String... values){
return Fp.all(new Fp.Map1<String,Boolean>(){
public Boolean apply(String a) {
try{ return a == null || confirm(a); }
catch(Exception x){ return false; }
}},
Arrays.asList(values));
}
public abstract boolean confirm(String v);
public abstract Type getType();
}
static class IntTest extends NumTest{
@Override public boolean confirm(String v) {
Integer.parseInt(v);
return true;
}
@Override public Type getType() { return Type.getType(null, NPrimitive.inst('i'), null); }
}
static class LongTest extends NumTest{
@Override public boolean confirm(String v) {
Long.parseLong(v);
return true;
}
@Override public Type getType() { return Type.getType(null, NPrimitive.inst('l'), null); }
}
static class FloatTest extends NumTest{
@Override public boolean confirm(String v) {
return Float.parseFloat(v) == Double.parseDouble(v);
}
@Override public Type getType() { return Type.getType(null, NPrimitive.inst('f'), null); }
}
static class DoubleTest extends NumTest{
@Override public boolean confirm(String v) {
double d = Double.parseDouble(v);
return !Double.isInfinite(d) && !Double.isNaN(d);
}
@Override public Type getType() { return Type.getType(null, NPrimitive.inst('d'), null); }
}
}