001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.k2js.translate.expression;
018
019 import com.google.dart.compiler.backend.js.ast.JsExpression;
020 import com.google.dart.compiler.backend.js.ast.JsInvocation;
021 import com.google.dart.compiler.backend.js.ast.JsName;
022 import com.google.dart.compiler.backend.js.ast.JsNameRef;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.annotations.Nullable;
025 import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
026 import org.jetbrains.jet.lang.psi.*;
027 import org.jetbrains.k2js.translate.context.TranslationContext;
028 import org.jetbrains.k2js.translate.general.AbstractTranslator;
029 import org.jetbrains.k2js.translate.general.Translation;
030 import org.jetbrains.k2js.translate.utils.BindingUtils;
031 import org.jetbrains.k2js.translate.utils.TranslationUtils;
032
033 import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
034
035 public final class PatternTranslator extends AbstractTranslator {
036
037 @NotNull
038 public static PatternTranslator newInstance(@NotNull TranslationContext context) {
039 return new PatternTranslator(context);
040 }
041
042 private PatternTranslator(@NotNull TranslationContext context) {
043 super(context);
044 }
045
046 @NotNull
047 public JsExpression translateIsExpression(@NotNull JetIsExpression expression) {
048 JsExpression left = Translation.translateAsExpression(expression.getLeftHandSide(), context());
049 JetTypeReference typeReference = expression.getTypeRef();
050 assert typeReference != null;
051 JsExpression result = translateIsCheck(left, typeReference);
052 if (expression.isNegated()) {
053 return negated(result);
054 }
055 return result;
056 }
057
058 @NotNull
059 public JsExpression translateIsCheck(@NotNull JsExpression subject, @NotNull JetTypeReference typeReference) {
060 JsExpression result = translateAsIntrinsicTypeCheck(subject, typeReference);
061 if (result != null) {
062 return result;
063 }
064 return translateAsIsCheck(subject, typeReference);
065 }
066
067 @NotNull
068 private JsExpression translateAsIsCheck(@NotNull JsExpression expressionToMatch,
069 @NotNull JetTypeReference typeReference) {
070 JsInvocation isCheck = new JsInvocation(context().namer().isOperationReference(),
071 expressionToMatch, getClassReference(typeReference));
072 if (isNullable(typeReference)) {
073 return addNullCheck(expressionToMatch, isCheck);
074 }
075 return isCheck;
076 }
077
078 @Nullable
079 private JsExpression translateAsIntrinsicTypeCheck(@NotNull JsExpression expressionToMatch,
080 @NotNull JetTypeReference typeReference) {
081 JsExpression result = null;
082 JsName className = getClassReference(typeReference).getName();
083 if (className.getIdent().equals("String")) {
084 result = typeof(expressionToMatch, program().getStringLiteral("string"));
085 }
086 if (className.getIdent().equals("Int")) {
087 result = typeof(expressionToMatch, program().getStringLiteral("number"));
088 }
089 return result;
090 }
091
092 @NotNull
093 private static JsExpression addNullCheck(@NotNull JsExpression expressionToMatch, @NotNull JsInvocation isCheck) {
094 return or(TranslationUtils.isNullCheck(expressionToMatch), isCheck);
095 }
096
097 private boolean isNullable(JetTypeReference typeReference) {
098 return BindingUtils.getTypeByReference(bindingContext(), typeReference).isNullable();
099 }
100
101 @NotNull
102 private JsNameRef getClassReference(@NotNull JetTypeReference typeReference) {
103 return getClassNameReferenceForTypeReference(typeReference);
104 }
105
106 @NotNull
107 private JsNameRef getClassNameReferenceForTypeReference(@NotNull JetTypeReference typeReference) {
108 ClassDescriptor referencedClass = BindingUtils.getClassDescriptorForTypeReference
109 (bindingContext(), typeReference);
110 return TranslationUtils.getQualifiedReference(context(), referencedClass);
111 }
112
113 @NotNull
114 public JsExpression translateExpressionPattern(@NotNull JsExpression expressionToMatch, @NotNull JetExpression patternExpression) {
115 JsExpression expressionToMatchAgainst = translateExpressionForExpressionPattern(patternExpression);
116 return equality(expressionToMatch, expressionToMatchAgainst);
117 }
118
119 @NotNull
120 public JsExpression translateExpressionForExpressionPattern(@NotNull JetExpression patternExpression) {
121 return Translation.translateAsExpression(patternExpression, context());
122 }
123 }