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
015package org.apache.tapestry5.internal.plastic;
016
017import java.util.HashMap;
018import java.util.Map;
019
020import 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")
028public 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}