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 }