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.lang;
022
023 import java.io.IOException;
024 import java.io.InputStream;
025 import java.lang.reflect.Method;
026 import java.lang.reflect.Modifier;
027 import java.util.ArrayList;
028 import java.util.List;
029 import java.util.Properties;
030
031 import csheets.CleanSheets;
032 import csheets.core.formula.BinaryOperator;
033 import csheets.core.formula.Function;
034 import csheets.core.formula.UnaryOperator;
035
036 /**
037 * A factory for creating certain types of language elements.
038 * @author Einar Pehrson
039 */
040 public class Language {
041
042 /** The singleton instance */
043 private static final Language instance = new Language();
044
045 /** The name of the file in which language properties are stored */
046 private static final String PROPERTIES_FILENAME = "res/language.props";
047
048 /** The unary operators that are supported by the language */
049 private List<UnaryOperator> unaryOperators = new ArrayList<UnaryOperator>();
050
051 /** The binary operators that are supported by the language */
052 private List<BinaryOperator> binaryOperators = new ArrayList<BinaryOperator>();
053
054 /** The functions that are supported by the language */
055 private List<Function> functions = new ArrayList<Function>();
056
057 /**
058 * Creates a new language.
059 */
060 private Language() {
061 // Loads properties
062 Properties language = new Properties();
063 InputStream stream = CleanSheets.class.getResourceAsStream(PROPERTIES_FILENAME);
064 if (stream != null) {
065 try {
066 language.load(stream);
067 } catch (IOException e) {
068 System.err.println("An I/O error occurred when loading language"
069 + " properties file (" + PROPERTIES_FILENAME + ").");
070 return;
071 } finally {
072 try {
073 if (stream != null)
074 stream.close();
075 } catch (IOException e) {}
076 }
077
078 // Loads elements
079 for (Object className : language.keySet()) {
080 // Loads class and instantiates element
081 Class elementClass;
082 Object element;
083 try {
084 elementClass = Class.forName(getClass().getPackage()
085 .getName() + "." + (String)className);
086 element = elementClass.newInstance();
087 } catch (Exception e) {
088 // Skip this element, regardless of what went wrong
089 continue;
090 }
091
092 // Stores element
093 if (Function.class.isAssignableFrom(elementClass))
094 functions.add(Function.class.cast(element));
095 if (BinaryOperator.class.isAssignableFrom(elementClass))
096 binaryOperators.add(BinaryOperator.class.cast(element));
097 if (UnaryOperator.class.isAssignableFrom(elementClass))
098 unaryOperators.add(UnaryOperator.class.cast(element));
099 }
100 } else
101 System.err.println("Could not find language properties file ("
102 + PROPERTIES_FILENAME + ").");
103
104 // Loads static methods from java.lang.Math that use double precision
105 for (Method method : Math.class.getMethods())
106 if (Modifier.isStatic(method.getModifiers()) &&
107 method.getReturnType() == Double.TYPE)
108 functions.add(new NumericFunction(method));
109 }
110
111 /**
112 * Returns the singleton instance.
113 * @return the singleton instance
114 */
115 public static Language getInstance() {
116 return instance;
117 }
118
119 /**
120 * Returns the unary operator with the given identifier.
121 * @return the unary operator with the given identifier
122 */
123 public UnaryOperator getUnaryOperator(String identifier) throws UnknownElementException {
124 for (UnaryOperator operator : unaryOperators)
125 if (identifier.equalsIgnoreCase(operator.getIdentifier()))
126 return operator; // .clone()
127 throw new UnknownElementException(identifier);
128 }
129
130 /**
131 * Returns the binary operator with the given identifier.
132 * @return the binary operator with the given identifier
133 */
134 public BinaryOperator getBinaryOperator(String identifier) throws UnknownElementException {
135 for (BinaryOperator operator : binaryOperators)
136 if (identifier.equalsIgnoreCase(operator.getIdentifier()))
137 return operator; // .clone()
138 throw new UnknownElementException(identifier);
139 }
140
141 /**
142 * Returns the function with the given identifier.
143 * @return the function with the given identifier
144 */
145 public Function getFunction(String identifier) throws UnknownElementException {
146 for (Function function : functions)
147 if (identifier.equalsIgnoreCase(function.getIdentifier()))
148 return function; // .clone()
149 throw new UnknownElementException(identifier);
150 }
151
152 /**
153 * Returns whether there is a function with the given identifier.
154 * @return whether there is a function with the given identifier
155 */
156 public boolean hasFunction(String identifier) {
157 try {
158 return getFunction(identifier) != null;
159 } catch (UnknownElementException e) {
160 return false;
161 }
162 }
163
164 /**
165 * Returns the functions that are supported by the syntax.
166 * @return the functions that are supported by the syntax
167 */
168 public Function[] getFunctions() {
169 return functions.toArray(new Function[functions.size()]);
170 }
171 }