1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xalan.internal.xsltc.compiler;
  22 
  23 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  24 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  25 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  26 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  27 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
  28 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  29 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  30 
  31 /**
  32  * @author Jacek Ambroziak
  33  * @author Santiago Pericas-Geertsen
  34  * @LastModified: Nov 2017
  35  */
  36 final class BinOpExpr extends Expression {
  37     public static final int PLUS  = 0;
  38     public static final int MINUS = 1;
  39     public static final int TIMES = 2;
  40     public static final int DIV   = 3;
  41     public static final int MOD   = 4;
  42 
  43     private static final String[] Ops = {
  44         "+", "-", "*", "/", "%"
  45     };
  46 
  47     private int _op;
  48     private Expression _left, _right;
  49 
  50     public BinOpExpr(int op, Expression left, Expression right) {
  51         _op = op;
  52         (_left = left).setParent(this);
  53         (_right = right).setParent(this);
  54     }
  55 
  56     /**
  57      * Returns true if this expressions contains a call to position(). This is
  58      * needed for context changes in node steps containing multiple predicates.
  59      */
  60     public boolean hasPositionCall() {
  61         if (_left.hasPositionCall()) return true;
  62         if (_right.hasPositionCall()) return true;
  63         return false;
  64     }
  65 
  66     /**
  67      * Returns true if this expressions contains a call to last()
  68      */
  69     public boolean hasLastCall() {
  70             return (_left.hasLastCall() || _right.hasLastCall());
  71     }
  72 
  73     public void setParser(Parser parser) {
  74         super.setParser(parser);
  75         _left.setParser(parser);
  76         _right.setParser(parser);
  77     }
  78 
  79     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  80         final Type tleft = _left.typeCheck(stable);
  81         final Type tright = _right.typeCheck(stable);
  82         final MethodType ptype = lookupPrimop(stable, Ops[_op],
  83                                               new MethodType(Type.Void,
  84                                                              tleft, tright));
  85         if (ptype != null) {
  86             final Type arg1 = ptype.argsType().get(0);
  87             if (!arg1.identicalTo(tleft)) {
  88                 _left = new CastExpr(_left, arg1);
  89             }
  90             final Type arg2 = ptype.argsType().get(1);
  91             if (!arg2.identicalTo(tright)) {
  92                 _right = new CastExpr(_right, arg1);
  93             }
  94             return _type = ptype.resultType();
  95         }
  96         throw new TypeCheckError(this);
  97     }
  98 
  99     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
 100         final InstructionList il = methodGen.getInstructionList();
 101 
 102         _left.translate(classGen, methodGen);
 103         _right.translate(classGen, methodGen);
 104 
 105         switch (_op) {
 106         case PLUS:
 107             il.append(_type.ADD());
 108             break;
 109         case MINUS:
 110             il.append(_type.SUB());
 111             break;
 112         case TIMES:
 113             il.append(_type.MUL());
 114             break;
 115         case DIV:
 116             il.append(_type.DIV());
 117             break;
 118         case MOD:
 119             il.append(_type.REM());
 120             break;
 121         default:
 122             ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_BINARY_OP_ERR, this);
 123             getParser().reportError(Constants.ERROR, msg);
 124         }
 125     }
 126 
 127     public String toString() {
 128         return Ops[_op] + '(' + _left + ", " + _right + ')';
 129     }
 130 }