001/* 002 * Copyright (c) 2005 Einar Pehrson <einar@pehrson.nu>. 003 * 004 * This file is part of 005 * CleanSheets - a spreadsheet application for the Java platform. 006 * 007 * CleanSheets is free software; you can redistribute it and/or modify 008 * it under the terms of the GNU General Public License as published by 009 * the Free Software Foundation; either version 2 of the License, or 010 * (at your option) any later version. 011 * 012 * CleanSheets is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * along with CleanSheets; if not, write to the Free Software 019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 020 */ 021package csheets.core.formula; 022 023import java.io.IOException; 024import java.io.ObjectInputStream; 025import java.io.ObjectOutputStream; 026 027import csheets.core.IllegalValueTypeException; 028import csheets.core.Value; 029import csheets.core.formula.compiler.IllegalFunctionCallException; 030import csheets.core.formula.lang.Language; 031import csheets.core.formula.lang.UnknownElementException; 032import csheets.core.formula.util.ExpressionVisitor; 033 034/** 035 * A call to a function in a formula. 036 * @author Einar Pehrson 037 */ 038public class FunctionCall implements Expression { 039 040 /** The unique version identifier used for serialization */ 041 private static final long serialVersionUID = 1666675675246822233L; 042 043 /** The function that is called */ 044 private transient Function function; 045 046 /** The arguments passed to the function */ 047 private Expression[] args; 048 049 /** 050 * Creates a new function call. 051 * @param function the function that is called 052 * @param args the arguments passed to the function 053 * @throws IllegalFunctionCallException if the arguments passed to the function did not match its parameters 054 */ 055 public FunctionCall(Function function, Expression... args) 056 throws IllegalFunctionCallException { 057 // Stores members 058 this.function = function; 059 this.args = args; 060 061 // Checks arguments against parameters 062 FunctionParameter[] params = function.getParameters(); 063 for (int i = 0; i < args.length; i++) 064 if (params.length <= i && !function.isVarArg()) 065 // Too many arguments 066 throw new IllegalFunctionCallException(function, null, args[i]); 067 for (int i = params.length - 1; i >= 0; i--) 068 if (i >= args.length && !params[i].isOptional()) 069 // Too few arguments 070 throw new IllegalFunctionCallException(function, params[i], null); 071 } 072 073 public Value evaluate() throws IllegalValueTypeException { 074 return function.applyTo(args); 075 } 076 077 /** 078 * Returns the function that is called. 079 * @return the function that is called 080 */ 081 public Function getFunction() { 082 return function; 083 } 084 085 /** 086 * Returns the arguments passed to the function. 087 * @return the arguments passed to the function 088 */ 089 public Expression[] getArguments() { 090 return args; 091 } 092 093 public Object accept(ExpressionVisitor visitor) { 094 return visitor.visitFunctionCall(this); 095 } 096 097 public String toString() { 098 String string = function.getIdentifier().toUpperCase() + "("; 099 for (int i = 0; i < args.length; i++) { 100 string += args[i]; 101 if (i + 1 < args.length) 102 string += "; "; 103 } 104 string += ")"; 105 return string; 106 } 107 108 /** 109 * Customizes deserialization by fetching the function from the language 110 * using the stored identifier. 111 * @param stream the object input stream from which the object is to be read 112 * @throws IOException If any of the usual Input/Output related exceptions occur 113 * @throws ClassNotFoundException If the class of a serialized object cannot be found. 114 */ 115 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 116 stream.defaultReadObject(); 117 String identifier = (String)stream.readObject(); 118 try { 119 function = Language.getInstance().getFunction(identifier); 120 } catch (UnknownElementException e) { 121 throw new IOException(e.toString()); 122 } 123 } 124 125 /** 126 * Customizes serialization by only writing the identifer of the function. 127 * @param stream the object output stream to which the object is to be written 128 * @throws IOException If any of the usual Input/Output related exceptions occur 129 */ 130 private void writeObject(ObjectOutputStream stream) throws IOException { 131 stream.defaultWriteObject(); 132 stream.writeObject(function.getIdentifier()); 133 } 134}