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 017package org.jetbrains.k2js.translate.operation; 018 019import com.google.common.collect.Lists; 020import com.google.dart.compiler.backend.js.ast.JsBinaryOperation; 021import com.google.dart.compiler.backend.js.ast.JsBinaryOperator; 022import com.google.dart.compiler.backend.js.ast.JsExpression; 023import com.google.dart.compiler.util.AstUtil; 024import org.jetbrains.annotations.NotNull; 025import org.jetbrains.jet.lang.psi.JetExpression; 026import org.jetbrains.jet.lang.psi.JetUnaryExpression; 027import org.jetbrains.jet.lang.types.expressions.OperatorConventions; 028import org.jetbrains.k2js.translate.context.TemporaryVariable; 029import org.jetbrains.k2js.translate.context.TranslationContext; 030import org.jetbrains.k2js.translate.general.AbstractTranslator; 031import org.jetbrains.k2js.translate.reference.CachedAccessTranslator; 032 033import java.util.List; 034 035import static org.jetbrains.k2js.translate.reference.AccessTranslationUtils.getCachedAccessTranslator; 036import static org.jetbrains.k2js.translate.utils.JsAstUtils.newSequence; 037import static org.jetbrains.k2js.translate.utils.PsiUtils.*; 038import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization; 039import static org.jetbrains.k2js.translate.utils.TranslationUtils.hasCorrespondingFunctionIntrinsic; 040 041// TODO: provide better increment translator logic 042public abstract class IncrementTranslator extends AbstractTranslator { 043 044 public static boolean isIncrement(@NotNull JetUnaryExpression expression) { 045 return OperatorConventions.INCREMENT_OPERATIONS.contains(getOperationToken(expression)); 046 } 047 048 @NotNull 049 public static JsExpression translate(@NotNull JetUnaryExpression expression, 050 @NotNull TranslationContext context) { 051 if (hasCorrespondingFunctionIntrinsic(context, expression)) { 052 return IntrinsicIncrementTranslator.doTranslate(expression, context); 053 } 054 return (new OverloadedIncrementTranslator(expression, context)).translateIncrementExpression(); 055 } 056 057 @NotNull 058 protected final JetUnaryExpression expression; 059 @NotNull 060 protected final CachedAccessTranslator accessTranslator; 061 062 protected IncrementTranslator(@NotNull JetUnaryExpression expression, 063 @NotNull TranslationContext context) { 064 super(context); 065 this.expression = expression; 066 JetExpression baseExpression = getBaseExpression(expression); 067 this.accessTranslator = getCachedAccessTranslator(baseExpression, context()); 068 } 069 070 @NotNull 071 protected JsExpression translateIncrementExpression() { 072 return withTemporariesInitialized(doTranslateIncrementExpression()); 073 } 074 075 @NotNull 076 private JsExpression doTranslateIncrementExpression() { 077 if (isPrefix(expression)) { 078 return asPrefix(); 079 } 080 return asPostfix(); 081 } 082 083 //TODO: decide if this expression can be optimised in case of direct access (not property) 084 @NotNull 085 private JsExpression asPrefix() { 086 // code fragment: expr(a++) 087 // generate: expr(a = a.inc(), a) 088 JsExpression getExpression = accessTranslator.translateAsGet(); 089 JsExpression reassignment = variableReassignment(getExpression); 090 JsExpression getNewValue = accessTranslator.translateAsGet(); 091 return new JsBinaryOperation(JsBinaryOperator.COMMA, reassignment, getNewValue); 092 } 093 094 //TODO: decide if this expression can be optimised in case of direct access (not property) 095 @NotNull 096 private JsExpression asPostfix() { 097 // code fragment: expr(a++) 098 // generate: expr( (t1 = a, t2 = t1, a = t1.inc(), t2) ) 099 TemporaryVariable t1 = context().declareTemporary(accessTranslator.translateAsGet()); 100 TemporaryVariable t2 = context().declareTemporary(t1.reference()); 101 JsExpression variableReassignment = variableReassignment(t1.reference()); 102 return AstUtil.newSequence(t1.assignmentExpression(), t2.assignmentExpression(), 103 variableReassignment, t2.reference()); 104 } 105 106 @NotNull 107 private JsExpression variableReassignment(@NotNull JsExpression toCallMethodUpon) { 108 JsExpression overloadedMethodCallOnPropertyGetter = operationExpression(toCallMethodUpon); 109 return accessTranslator.translateAsSet(overloadedMethodCallOnPropertyGetter); 110 } 111 112 @NotNull 113 private JsExpression withTemporariesInitialized(@NotNull JsExpression expression) { 114 List<TemporaryVariable> temporaries = accessTranslator.declaredTemporaries(); 115 List<JsExpression> expressions = Lists.newArrayList(temporariesInitialization(temporaries)); 116 expressions.add(expression); 117 return newSequence(expressions); 118 } 119 120 @NotNull 121 abstract JsExpression operationExpression(@NotNull JsExpression receiver); 122}