| /* |
| * Copyright 2008 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.dev.jjs.ast; |
| |
| import com.google.gwt.dev.jjs.SourceOrigin; |
| import com.google.gwt.dev.util.StringInterner; |
| import com.google.gwt.thirdparty.guava.common.collect.ImmutableCollection; |
| import com.google.gwt.thirdparty.guava.common.collect.ImmutableList; |
| import com.google.gwt.thirdparty.guava.common.collect.Maps; |
| |
| import java.util.Map; |
| |
| /** |
| * Base class for all Java primitive types. |
| */ |
| public class JPrimitiveType extends JType { |
| private static final Map<String, JPrimitiveType> primitiveTypeByName = Maps.newHashMap(); |
| |
| /* |
| * Primitive types are static singletons. Serialization via readResolve(). |
| */ |
| public static final JPrimitiveType BOOLEAN = new JPrimitiveType( |
| "boolean", "Z", "java.lang.Boolean", JBooleanLiteral.FALSE, Coercion.TO_BOOLEAN); |
| public static final JPrimitiveType BYTE = |
| new JPrimitiveType("byte", "B", "java.lang.Byte", JIntLiteral.ZERO, Coercion.TO_BYTE); |
| public static final JPrimitiveType CHAR = |
| new JPrimitiveType("char", "C", "java.lang.Character", JCharLiteral.NULL, Coercion.TO_CHAR); |
| public static final JPrimitiveType DOUBLE = new JPrimitiveType( |
| "double", "D", "java.lang.Double", JDoubleLiteral.ZERO, Coercion.TO_DOUBLE); |
| public static final JPrimitiveType FLOAT = |
| new JPrimitiveType("float", "F", "java.lang.Float", JFloatLiteral.ZERO, Coercion.TO_FLOAT); |
| public static final JPrimitiveType INT = |
| new JPrimitiveType("int", "I", "java.lang.Integer", JIntLiteral.ZERO, Coercion.TO_INT); |
| public static final JPrimitiveType LONG = |
| new JPrimitiveType("long", "J", "java.lang.Long", JLongLiteral.ZERO, Coercion.TO_LONG); |
| public static final JPrimitiveType SHORT = |
| new JPrimitiveType("short", "S", "java.lang.Short", JIntLiteral.ZERO, Coercion.TO_SHORT); |
| public static final JPrimitiveType VOID = |
| new JPrimitiveType("void", "V", "java.lang.VOID", null, Coercion.TO_VOID); |
| |
| public static final ImmutableCollection<JPrimitiveType> types = ImmutableList.of(BOOLEAN, BYTE, |
| CHAR, DOUBLE, FLOAT, INT, LONG, SHORT, VOID); |
| |
| private final transient JValueLiteral defaultValue; |
| private final transient String signatureName; |
| private final transient String wrapperTypeName; |
| private final transient Coercion coercion; |
| |
| private JPrimitiveType(String name, String signatureName, String wrapperTypeName, |
| JValueLiteral defaultValue, Coercion coercion) { |
| super(SourceOrigin.UNKNOWN, name); |
| this.defaultValue = defaultValue; |
| this.signatureName = StringInterner.get().intern(signatureName); |
| this.wrapperTypeName = StringInterner.get().intern(wrapperTypeName); |
| this.coercion = coercion; |
| primitiveTypeByName.put(this.name, this); |
| } |
| |
| @Override |
| public boolean canBeNull() { |
| return false; |
| } |
| |
| @Override |
| public boolean isArrayType() { |
| return false; |
| } |
| |
| @Override |
| public boolean isPrimitiveType() { |
| return true; |
| } |
| |
| @Override |
| public boolean isJsType() { |
| return false; |
| } |
| |
| @Override |
| public boolean isJsFunction() { |
| return false; |
| } |
| |
| @Override |
| public boolean isJsFunctionImplementation() { |
| return false; |
| } |
| |
| @Override |
| public boolean isJsNative() { |
| return false; |
| } |
| |
| @Override |
| public boolean canBeImplementedExternally() { |
| return false; |
| } |
| |
| @Override |
| public boolean canBeSubclass() { |
| return false; |
| } |
| |
| public JValueLiteral coerce(JValueLiteral literal) { |
| return this.coercion.coerce(literal); |
| } |
| |
| @Override |
| public final JLiteral getDefaultValue() { |
| return defaultValue; |
| } |
| |
| @Override |
| public String getJavahSignatureName() { |
| return signatureName; |
| } |
| |
| @Override |
| public String getJsniSignatureName() { |
| return signatureName; |
| } |
| |
| @Override |
| public JEnumType isEnumOrSubclass() { |
| return null; |
| } |
| |
| @Override |
| public JPrimitiveType strengthenToNonNull() { |
| return this; |
| } |
| |
| public String getWrapperTypeName() { |
| return wrapperTypeName; |
| } |
| |
| @Override |
| public boolean isFinal() { |
| return true; |
| } |
| |
| @Override |
| public boolean isJsoType() { |
| return false; |
| } |
| |
| @Override |
| public boolean canBeReferencedExternally() { |
| return this != JPrimitiveType.LONG; |
| } |
| |
| @Override |
| public boolean isJavaLangObject() { |
| return false; |
| } |
| |
| @Override |
| public void traverse(JVisitor visitor, Context ctx) { |
| if (visitor.visit(this, ctx)) { |
| } |
| visitor.endVisit(this, ctx); |
| } |
| |
| /** |
| * Returns the JPrimitiveType instance corresponding to {@code typeName} or {@code null} if |
| * typeName is not the name of a primitive type. |
| */ |
| public static JPrimitiveType getType(String typeName) { |
| return primitiveTypeByName.get(typeName); |
| } |
| |
| /** |
| * Canonicalize to singleton; uses {@link JType#name}. |
| */ |
| private Object readResolve() { |
| return primitiveTypeByName.get(name); |
| } |
| |
| private enum Coercion { |
| TO_CHAR() { |
| @Override |
| JValueLiteral coerce(JValueLiteral literal) { |
| if (literal instanceof JCharLiteral) { |
| return literal; |
| } |
| |
| Object valueObject = literal.getValueObj(); |
| if (valueObject instanceof Number) { |
| return new JCharLiteral( |
| literal.getSourceInfo(), (char) ((Number) valueObject).intValue()); |
| } |
| return null; |
| } |
| }, |
| TO_INT() { |
| @Override |
| JValueLiteral coerce(JValueLiteral literal) { |
| Object valueObject = literal.getValueObj(); |
| if (!(valueObject instanceof Number) && !(valueObject instanceof Character)) { |
| return null; |
| } |
| int value = 0; |
| if (valueObject instanceof Number) { |
| value = ((Number) valueObject).intValue(); |
| } else if (valueObject instanceof Character) { |
| value = ((Character) valueObject).charValue(); |
| } |
| return new JIntLiteral(literal.getSourceInfo(), value); |
| } |
| }, |
| TO_BYTE() { |
| @Override |
| JValueLiteral coerce(JValueLiteral literal) { |
| Object valueObject = literal.getValueObj(); |
| if (!(valueObject instanceof Number) && !(valueObject instanceof Character)) { |
| return null; |
| } |
| byte value = 0; |
| if (valueObject instanceof Number) { |
| value = ((Number) valueObject).byteValue(); |
| } else if (valueObject instanceof Character) { |
| value = (byte) ((Character) valueObject).charValue(); |
| } |
| return new JIntLiteral(literal.getSourceInfo(), value); |
| } |
| }, |
| TO_SHORT() { |
| @Override |
| JValueLiteral coerce(JValueLiteral literal) { |
| Object valueObject = literal.getValueObj(); |
| if (!(valueObject instanceof Number) && !(valueObject instanceof Character)) { |
| return null; |
| } |
| short value = 0; |
| if (valueObject instanceof Number) { |
| value = ((Number) valueObject).shortValue(); |
| } else if (valueObject instanceof Character) { |
| value = (short) ((Character) valueObject).charValue(); |
| } |
| return new JIntLiteral(literal.getSourceInfo(), value); |
| } |
| }, |
| TO_LONG() { |
| @Override |
| JValueLiteral coerce(JValueLiteral literal) { |
| Object valueObject = literal.getValueObj(); |
| if (!(valueObject instanceof Number) && !(valueObject instanceof Character)) { |
| return null; |
| } |
| long value = 0; |
| if (valueObject instanceof Number) { |
| value = ((Number) valueObject).longValue(); |
| } else if (valueObject instanceof Character) { |
| value = (long) ((Character) valueObject).charValue(); |
| } |
| return new JLongLiteral(literal.getSourceInfo(), value); |
| } |
| }, |
| TO_FLOAT() { |
| @Override |
| JValueLiteral coerce(JValueLiteral literal) { |
| Object valueObject = literal.getValueObj(); |
| if (!(valueObject instanceof Number) && !(valueObject instanceof Character)) { |
| return null; |
| } |
| float value = 0; |
| if (valueObject instanceof Number) { |
| value = ((Number) valueObject).floatValue(); |
| } else if (valueObject instanceof Character) { |
| value = (float) ((Character) valueObject).charValue(); |
| } |
| return new JFloatLiteral(literal.getSourceInfo(), value); |
| } |
| }, |
| TO_DOUBLE() { |
| @Override |
| JValueLiteral coerce(JValueLiteral literal) { |
| Object valueObject = literal.getValueObj(); |
| if (!(valueObject instanceof Number) && !(valueObject instanceof Character)) { |
| return null; |
| } |
| double value = 0; |
| if (valueObject instanceof Number) { |
| value = ((Number) valueObject).doubleValue(); |
| } else if (valueObject instanceof Character) { |
| value = (double) ((Character) valueObject).charValue(); |
| } |
| return new JDoubleLiteral(literal.getSourceInfo(), value); |
| } |
| }, |
| TO_BOOLEAN() { |
| @Override |
| public JValueLiteral coerce(JValueLiteral literal) { |
| if (literal instanceof JBooleanLiteral) { |
| return literal; |
| } |
| return null; |
| } |
| }, |
| TO_VOID() { |
| @Override |
| public JValueLiteral coerce(JValueLiteral literal) { |
| return null; |
| } |
| }; |
| |
| /** |
| * Coerces a literal into a literal of (possibly) a different type; returns {@code null} if |
| * coercion is not valid. |
| */ |
| abstract JValueLiteral coerce(JValueLiteral literal); |
| } |
| } |