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.lang; 022 023import java.io.IOException; 024import java.io.InputStream; 025import java.lang.reflect.Method; 026import java.lang.reflect.Modifier; 027import java.util.ArrayList; 028import java.util.List; 029import java.util.Properties; 030 031import csheets.CleanSheets; 032import csheets.core.formula.BinaryOperator; 033import csheets.core.formula.Function; 034import csheets.core.formula.UnaryOperator; 035 036/** 037 * A factory for creating certain types of language elements. 038 * @author Einar Pehrson 039 */ 040public 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}