/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free SoftwareFoundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.es.parser; import com.caucho.es.ESBase; import com.caucho.es.ESException; import com.caucho.es.ESNumber; import com.caucho.es.ESWrapperException; import java.io.IOException; /** * Expr is an intermediate form representing an expression. */ class BinaryExpr extends Expr { Expr left; Expr right; int op; String temp; boolean isSimple; protected BinaryExpr(Block block, Expr left, Expr right, int op) { super(block); this.left = left; this.right = right; this.op = op; isSimple = left.isSimple(); if ((op == Lexer.AND || op == Lexer.OR) && ! isSimple) temp = block.function.getTemp(); } static Expr create(Block block, Expr left, Expr right, int op) throws ESException { if (left != null) left.setUsed(); if (right != null) right.setUsed(); if (! (left instanceof LiteralExpr) || ! (right instanceof LiteralExpr)) return new BinaryExpr(block, left, right, op); ESBase lvalue = ((LiteralExpr) left).getLiteral(); ESBase rvalue = ((LiteralExpr) right).getLiteral(); ESBase value; try { switch (op) { case '*': value = ESNumber.create(lvalue.toNum() * rvalue.toNum()); break; case '/': value = ESNumber.create(lvalue.toNum() / rvalue.toNum()); break; case '-': value = ESNumber.create(lvalue.toNum() - rvalue.toNum()); break; case '%': value = ESNumber.create(lvalue.toNum() % rvalue.toNum()); break; case Lexer.LSHIFT: value = ESNumber.create(lvalue.toInt32() << rvalue.toInt32()); break; case Lexer.RSHIFT: value = ESNumber.create(lvalue.toInt32() >> rvalue.toInt32()); break; case Lexer.URSHIFT: value = ESNumber.create(lvalue.toInt32() >>> rvalue.toInt32()); break; case '&': value = ESNumber.create(lvalue.toInt32() & rvalue.toInt32()); break; case '|': value = ESNumber.create(lvalue.toInt32() | rvalue.toInt32()); break; case '^': value = ESNumber.create(lvalue.toInt32() ^ rvalue.toInt32()); break; case Lexer.AND: value = lvalue.toBoolean() ? rvalue : lvalue; break; case Lexer.OR: value = lvalue.toBoolean() ? lvalue : rvalue; break; case ',': value = rvalue; break; default: throw new RuntimeException("" + (char) op); } } catch (Throwable e) { throw new ESWrapperException(e); } return new LiteralExpr(block, value); } int getType() { switch (op) { case '*': case '/': case '%': return TYPE_NUMBER; case '-': if (left.getType() == TYPE_INTEGER && right.getType() == TYPE_INTEGER) return TYPE_INTEGER; else return TYPE_NUMBER; case Lexer.LSHIFT: case Lexer.RSHIFT: case Lexer.URSHIFT: case '&': case '|': case '^': return TYPE_INTEGER; case Lexer.AND: case Lexer.OR: if (left.getType() == right.getType()) return left.getType(); else if (left.isNum() && right.isNum()) return TYPE_NUMBER; else return TYPE_ES; case ',': return TYPE_ES; default: throw new RuntimeException("" + (char) op + " " + op); } } void exprStatement(Function fun) throws ESException { switch (op) { default: left.exprStatement(fun); right.exprStatement(fun); break; } } void printNumImpl() throws IOException { cl.print("("); switch (op) { case '*': case '/': case '-': case '%': left.printNum(); cl.print(" " + (char) op + " "); right.printNum(); break; case Lexer.AND: if (isSimple) { left.printBoolean(); cl.print(" ? "); right.printNum(); cl.print(":"); left.printNum(); } else { cl.print("(" + temp + " = "); left.print(); cl.print(").toBoolean() ? "); right.printNum(); cl.print(":" + temp + ".toNum()"); } break; case Lexer.OR: if (isSimple) { left.printBoolean(); cl.print(" ? "); left.printNum(); cl.print(":"); right.printNum(); } else { cl.print("(" + temp + " = "); left.print(); cl.print(").toBoolean() ? " + temp + ".toNum() : "); right.printNum(); } break; default: throw new IOException("foo"); } cl.print(")"); } void printInt32Impl() throws IOException { cl.print("("); switch (op) { case '-': left.printInt32(); cl.print(" " + (char) op + " "); right.printInt32(); break; case Lexer.LSHIFT: left.printInt32(); cl.print(" << "); right.printInt32(); break; case Lexer.RSHIFT: left.printInt32(); cl.print(" >> "); right.printInt32(); break; case Lexer.URSHIFT: left.printInt32(); cl.print(" >>> "); right.printInt32(); break; case '&': case '|': case '^': left.printInt32(); cl.print(" " + (char) op + " "); right.printInt32(); break; case Lexer.AND: if (isSimple) { left.printBoolean(); cl.print(" ? "); right.printInt32(); cl.print(":"); left.printInt32(); } else { cl.print("(" + temp + " = "); left.print(); cl.print(").toBoolean() ? "); right.printInt32(); cl.print(":" + temp + ".toInt32()"); } break; case Lexer.OR: if (isSimple) { left.printBoolean(); cl.print(" ? "); left.printInt32(); cl.print(":"); right.printInt32(); } else { cl.print("(" + temp + " = "); left.print(); cl.print(").toBoolean() ? " + temp + ".toInt32() : "); right.printInt32(); } break; default: throw new IOException("foo"); } cl.print(")"); } void printBoolean() throws IOException { switch (op) { case Lexer.AND: cl.print("("); left.printBoolean(); cl.print(" && "); right.printBoolean(); cl.print(")"); break; case Lexer.OR: cl.print("("); left.printBoolean(); cl.print(" || "); right.printBoolean(); cl.print(")"); break; default: super.printBoolean(); } } void printBooleanImpl() throws IOException { cl.print("("); switch (op) { case Lexer.AND: left.printBoolean(); cl.print(" && "); right.printBoolean(); break; case Lexer.OR: left.printBoolean(); cl.print(" || "); right.printBoolean(); break; default: throw new IOException("foo"); } cl.print(")"); } void printImpl() throws IOException { switch (op) { case Lexer.AND: if (isSimple) { left.printBoolean(); cl.print(" ? "); right.print(); cl.print(":"); left.print(); } else { cl.print("((" + temp + " = "); left.print(); cl.print(").toBoolean() ? "); right.print(); cl.print(":" + temp + ")"); } break; case Lexer.OR: if (isSimple) { left.printBoolean(); cl.print(" ? "); left.print(); cl.print(":"); right.print(); } else { cl.print("((" + temp + " = "); left.print(); cl.print(").toBoolean() ? " + temp + " : "); right.print(); cl.print(")"); } break; case ',': cl.print("_env.comma("); left.print(); cl.print(", "); right.print(); cl.print(")"); break; default: throw new IOException("foo"); } } }