001    // Copyright 2011 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    // http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry5.internal.plastic;
016    
017    import java.util.HashMap;
018    import java.util.Map;
019    
020    import org.apache.tapestry5.internal.plastic.asm.Opcodes;
021    
022    /**
023     * Collects together information needed to write code that involves primitive types, including
024     * moving between wrapper types and primitive values, or extracting a primitive value from
025     * the {@link StaticContext}.
026     */
027    @SuppressWarnings("rawtypes")
028    public enum PrimitiveType implements Opcodes
029    {
030        VOID("void", "V", void.class, Void.class, null, null, ILOAD, ISTORE, RETURN),
031    
032        BOOLEAN("boolean", "Z", boolean.class, Boolean.class, "booleanValue", "getBoolean", ILOAD, ISTORE, IRETURN),
033    
034        CHAR("char", "C", char.class, Character.class, "charValue", "getChar", ILOAD, ISTORE, IRETURN),
035    
036        BYTE("byte", "B", byte.class, Byte.class, "byteValue", "getByte", ILOAD, ISTORE, IRETURN),
037    
038        SHORT("short", "S", short.class, Short.class, "shortValue", "getShort", ILOAD, ISTORE, IRETURN),
039    
040        INT("int", "I", int.class, Integer.class, "intValue", "getInt", ILOAD, ISTORE, IRETURN),
041    
042        FLOAT("float", "F", float.class, Float.class, "floatValue", "getFloat", FLOAD, FSTORE, FRETURN),
043    
044        LONG("long", "J", long.class, Long.class, "longValue", "getLong", LLOAD, LSTORE, LRETURN),
045    
046        DOUBLE("double", "D", double.class, Double.class, "doubleValue", "getDouble", DLOAD, DSTORE, DRETURN);
047    
048        /**
049         * @param name
050         *            the Java source name for the type
051         * @param descriptor
052         *            Java descriptor for the type ('Z', 'I', etc.)
053         * @param primitiveType
054         *            TODO
055         * @param wrapperType
056         *            wrapper type, e.g., java.lang.Integer
057         * @param toValueMethodName
058         *            name of method of wrapper class to extract primitive value
059         * @param getFromStaticContextMethodName
060         *            name of method of {@link StaticContext} used to extract primitive context value
061         * @param loadOpcode
062         *            Correct opcode for loading an argument or local variable onto the stack (ILOAD, LLOAD, FLOAD or
063         *            DLOAD)
064         * @param storeOpcode
065         *            matching opcode for storing a value to a local variable (ISTORE, LSTORE, FSTORE or DSTORE)
066         * @param returnOpcode
067         *            Correct opcode for returning the top value on the stack (IRETURN, LRETURN, FRETURN
068         *            or DRETURN)
069         */
070        private PrimitiveType(String name, String descriptor, Class primitiveType, Class wrapperType,
071                String toValueMethodName, String getFromStaticContextMethodName, int loadOpcode, int storeOpcode,
072                int returnOpcode)
073        {
074            this.name = name;
075            this.descriptor = descriptor;
076            this.primitiveType = primitiveType;
077            this.wrapperType = wrapperType;
078            this.wrapperInternalName = wrapperType == null ? null : PlasticInternalUtils.toInternalName(wrapperType
079                    .getName());
080            this.toValueMethodName = toValueMethodName;
081            this.getFromStaticContextMethodName = getFromStaticContextMethodName;
082            this.loadOpcode = loadOpcode;
083            this.storeOpcode = storeOpcode;
084            this.returnOpcode = returnOpcode;
085    
086            this.valueOfMethodDescriptor = String.format("(%s)L%s;", descriptor, wrapperInternalName);
087            this.toValueMethodDescriptor = "()" + descriptor;
088            this.getFromStaticContextMethodDescriptor = "(I)" + descriptor;
089        }
090    
091        public final String name, descriptor, wrapperInternalName, valueOfMethodDescriptor, toValueMethodName,
092                getFromStaticContextMethodName, toValueMethodDescriptor, getFromStaticContextMethodDescriptor;
093    
094        public final Class primitiveType, wrapperType;
095    
096        public final int loadOpcode, storeOpcode, returnOpcode;
097    
098        private static final Map<String, PrimitiveType> BY_NAME = new HashMap<String, PrimitiveType>();
099        private static final Map<String, PrimitiveType> BY_DESC = new HashMap<String, PrimitiveType>();
100        private static final Map<Class, PrimitiveType> BY_PRIMITIVE_TYPE = new HashMap<Class, PrimitiveType>();
101    
102        static
103        {
104            for (PrimitiveType type : values())
105            {
106                BY_NAME.put(type.name, type);
107                BY_DESC.put(type.descriptor, type);
108                BY_PRIMITIVE_TYPE.put(type.primitiveType, type);
109            }
110        }
111    
112        public boolean isWide()
113        {
114            return this == LONG || this == DOUBLE;
115        }
116    
117        /**
118         * Returns the primitive type matching the given type name or null for a non-primitive type (an array type,
119         * or an class name).
120         * 
121         * @param name
122         *            possible primitive name
123         * @return the type or null
124         */
125        public static PrimitiveType getByName(String name)
126        {
127            return BY_NAME.get(name);
128        }
129    
130        public static PrimitiveType getByPrimitiveType(Class primitiveType)
131        {
132            return BY_PRIMITIVE_TYPE.get(primitiveType);
133        }
134    }