001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: BinOpExpr.java 468650 2006-10-28 07:03:30Z minchau $
020     */
021    
022    package org.apache.xalan.xsltc.compiler;
023    
024    import org.apache.bcel.generic.InstructionList;
025    import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
026    import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
027    import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
028    import org.apache.xalan.xsltc.compiler.util.MethodType;
029    import org.apache.xalan.xsltc.compiler.util.Type;
030    import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
031    
032    /**
033     * @author Jacek Ambroziak
034     * @author Santiago Pericas-Geertsen
035     */
036    final class BinOpExpr extends Expression {
037        public static final int PLUS  = 0;
038        public static final int MINUS = 1;
039        public static final int TIMES = 2;
040        public static final int DIV   = 3;
041        public static final int MOD   = 4;
042            
043        private static final String[] Ops = {
044            "+", "-", "*", "/", "%"
045        };
046    
047        private int _op;
048        private Expression _left, _right;
049            
050        public BinOpExpr(int op, Expression left, Expression right) {
051            _op = op;
052            (_left = left).setParent(this);
053            (_right = right).setParent(this);
054        }
055    
056        /**
057         * Returns true if this expressions contains a call to position(). This is
058         * needed for context changes in node steps containing multiple predicates.
059         */
060        public boolean hasPositionCall() {
061            if (_left.hasPositionCall()) return true;
062            if (_right.hasPositionCall()) return true;
063            return false;
064        }
065    
066        /**
067         * Returns true if this expressions contains a call to last()
068         */
069        public boolean hasLastCall() {
070                return (_left.hasLastCall() || _right.hasLastCall());
071        }
072        
073        public void setParser(Parser parser) {
074            super.setParser(parser);
075            _left.setParser(parser);
076            _right.setParser(parser);
077        }
078        
079        public Type typeCheck(SymbolTable stable) throws TypeCheckError {
080            final Type tleft = _left.typeCheck(stable); 
081            final Type tright = _right.typeCheck(stable);
082            final MethodType ptype = lookupPrimop(stable, Ops[_op],
083                                                  new MethodType(Type.Void,
084                                                                 tleft, tright)); 
085            if (ptype != null) {
086                final Type arg1 = (Type) ptype.argsType().elementAt(0);
087                if (!arg1.identicalTo(tleft)) {
088                    _left = new CastExpr(_left, arg1);
089                }
090                final Type arg2 = (Type) ptype.argsType().elementAt(1);
091                if (!arg2.identicalTo(tright)) {
092                    _right = new CastExpr(_right, arg1);
093                }
094                return _type = ptype.resultType();
095            }
096            throw new TypeCheckError(this);
097        }
098    
099        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    }