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 */
021 package csheets.core.formula;
022
023 import java.io.IOException;
024 import java.io.ObjectInputStream;
025 import java.io.ObjectOutputStream;
026
027 import csheets.core.IllegalValueTypeException;
028 import csheets.core.Value;
029 import csheets.core.formula.compiler.IllegalFunctionCallException;
030 import csheets.core.formula.lang.Language;
031 import csheets.core.formula.lang.UnknownElementException;
032 import csheets.core.formula.util.ExpressionVisitor;
033
034 /**
035 * A call to a function in a formula.
036 * @author Einar Pehrson
037 */
038 public 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 }