    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}