/* * 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.ESException; import com.caucho.es.ESId; import com.caucho.es.wrapper.ESMethodDescriptor; import java.io.IOException; import java.util.ArrayList; /** * Represents a method call. Both Java calls and JavaScript calls are * handled here. */ class CallExpr extends Expr { protected Expr term; private Expr field; private boolean isNew; protected boolean isTop; protected ArrayList args = new ArrayList(); protected TypeExpr typeExpr; protected boolean isCalculated; // The Java method if we can determine direct Java call. protected ESMethodDescriptor method; CallExpr(Block block, Expr term, Expr field, boolean isNew) throws ESException { super(block); this.term = term; this.field = field; this.isNew = isNew; if (term != null) term.setUsed(); if (field != null) field.setUsed(); if (term == null || ! (term.getTypeExpr() instanceof JavaTypeExpr)) block.function.setCall(); } void exprStatement(Function fun) throws ESException { isTop = true; noValue = true; fun.addExpr(this); } /** * Returns the javascript type for the expression * * @return a javascript type. */ int getType() { calculateType(); return type; } /** * Returns the type expression of the call. * * @return a type expression. */ Expr getTypeExpr() { calculateType(); return typeExpr; } /** * Calculate the return type of the expression. */ private void calculateType() { boolean isStatic = false; if (isCalculated) return; isCalculated = true; Class javaClass = term.getJavaClass(); if (term instanceof JavaClassExpr) { isStatic = true; javaClass = ((JavaClassExpr) term).getJavaClass(); } if (javaClass == null || field == null || ! (field instanceof LiteralExpr) || term.getType() != TYPE_JAVA && ! isStatic) { return; } LiteralExpr lit = (LiteralExpr) field; String name = lit.getLiteral().toString(); method = JavaMethod.bestMethod(javaClass, name, isStatic, args); // exception if can't find method if (method != null) { Class returnType = method.getReturnType(); if (returnType.equals(void.class)) type = TYPE_VOID; else if (returnType.equals(int.class)) type = TYPE_INTEGER; else if (returnType.equals(double.class)) type = TYPE_NUMBER; else if (returnType.equals(boolean.class)) type = TYPE_BOOLEAN; else { type = TYPE_JAVA; this.javaType = returnType; } typeExpr = new JavaTypeExpr(block, returnType); } } void printBooleanImpl() throws IOException { printJavaImpl(); } void printInt32Impl() throws IOException { printJavaImpl(); } void printNumImpl() throws IOException { printJavaImpl(); } /** * Generates code for the call, producing a JavaScript result. */ void printImpl() throws IOException { if (term instanceof IdExpr && field == null && ! ((IdExpr) term).isJavaLocal()) { ESId id = ((IdExpr) term).getId(); field = new LiteralExpr(block, id); term = null; } if (term != null) { if (isNew) cl.print("_call.doNew("); else cl.print("_call.call("); term.print(); if (field != null) { cl.print(", "); field.printStr(); } } else if (function.isGlobalScope() && withDepth == 0) { if (isNew) cl.print("_call.doNew(_env.global, "); else cl.print("_call.call(_env.global, "); field.printStr(); } else { if (isNew) cl.print("_call.newScope("); else cl.print("_call.callScope("); field.printStr(); } int argCount = function.cl.getCallDepth(); cl.print(", " + argCount); for (int i = 0; i < args.size() && i < 3; i++) { Expr expr = (Expr) args.get(i); cl.print(", "); function.cl.pushCall(); expr.print(); } if (args.size() >= 3) cl.print(", 3"); for (int i = 3; i < args.size(); i++) { Expr expr = (Expr) args.get(i); cl.print("+ _call.arg(" + (i + argCount) + ", "); function.cl.pushCall(); expr.print(); cl.print(")"); } function.cl.popCall(args.size()); cl.print(")"); if (isTop) cl.println(";"); } void printStringImpl() throws IOException { if (String.class.equals(getJavaClass())) printJavaImpl(); else { cl.print("String.valueOf("); printJavaImpl(); cl.print(")"); } } /** * Generates code for the call, producing a Java result. */ void printJavaImpl() throws IOException { if (method.isStaticVirtual()) { cl.print(method.getMethodClassName()); } else { if (term instanceof JavaClassExpr) cl.print(method.getMethodClassName()); else { term.printJava(); } } cl.print('.'); cl.print(method.getName()); cl.print("("); boolean isFirst = true; if (method.isStaticVirtual()) { cl.print("("); printJavaClass(method.getDeclaringClass()); cl.print(")"); isFirst = false; term.printJava(); } Class []params = null; if (method != null) params = method.getParameterTypes(); for (int i = 0; i < args.size(); i++) { Expr expr = (Expr) args.get(i); if (! isFirst) cl.print(", "); isFirst = false; if (params == null) expr.printJava(); else if (params[i].equals(String.class)) { expr.printJavaString(); } else if (! params[i].isPrimitive()) { cl.print("("); printJavaClass(params[i]); cl.print(")"); expr.printJava(); } else if (params[i].equals(int.class)) expr.printInt32(); else if (params[i].equals(long.class)) expr.printInt64(); else if (params[i].equals(boolean.class)) expr.printBoolean(); else if (params[i].equals(double.class)) expr.printNum(); else expr.printJava(); } cl.print(")"); if (isTop) cl.println(";"); } /** * adds a new call parameter */ void addCallParam(Expr param) { param.setUsed(); args.add(param); } }