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.compiler;
022
023import java.io.IOException;
024import java.io.InputStream;
025import java.util.ArrayList;
026import java.util.List;
027import java.util.Properties;
028
029import csheets.CleanSheets;
030import csheets.core.Cell;
031import csheets.core.formula.Expression;
032import csheets.core.formula.Formula;
033
034/**
035 * A compiler that generates formulas from strings.
036 * @author Einar Pehrson
037 */
038public class FormulaCompiler {
039
040        /** The singleton instance */
041        private static final FormulaCompiler instance = new FormulaCompiler();
042
043        /** The name of the file in which compiler properties are stored */
044        private static final String PROPERTIES_FILENAME = "res/compilers.props";
045
046        /** The expression compilers used to compile formulas */
047        private List<ExpressionCompiler> compilers = new ArrayList<ExpressionCompiler>();
048        
049        /**
050         * Creates the formula compiler.
051         */
052        private FormulaCompiler() {
053                // Loads properties
054                Properties compilerProps = new Properties();
055                InputStream stream = CleanSheets.class.getResourceAsStream(PROPERTIES_FILENAME);
056                if (stream != null) {
057                        try {
058                                compilerProps.load(stream);
059                        } catch (IOException e) {
060                                System.err.println("An I/O error occurred when loading compiler"
061                                        + " properties file (" + PROPERTIES_FILENAME + ").");
062                                return;
063                        } finally {
064                                try {
065                                        if (stream != null)
066                                                stream.close();
067                                } catch (IOException e) {}
068                        }
069
070                        // Loads elements
071                        for (Object className : compilerProps.keySet()) {
072                                // Loads class and instantiates element
073                                Class elementClass;
074                                Object element;
075                                try {
076                                        elementClass = Class.forName(getClass().getPackage()
077                                                .getName() + "." + (String)className);
078                                        element = elementClass.newInstance();
079                                } catch (Exception e) {
080                                        // Skip this element, regardless of what went wrong
081                                        e.printStackTrace();
082                                        continue;
083                                }
084
085                                // Stores element
086                                if (ExpressionCompiler.class.isAssignableFrom(elementClass))
087                                        compilers.add(ExpressionCompiler.class.cast(element));
088                        }
089                } else
090                        System.err.println("Could not find compiler properties file ("
091                                + PROPERTIES_FILENAME + ").");
092        }
093
094        /**
095         * Returns the singleton instance.
096         * @return the singleton instance
097         */
098        public static FormulaCompiler getInstance() {
099                return instance;
100        }
101
102        /**
103         * Compiles a formula for the given cell from the given string.
104         * @param cell the cell for which a formula is to be generated
105         * @param source a string representing the formula to be compiled
106         * @return a list of lexical tokens
107         * @throws FormulaCompilationException if the formula could not be compiled
108         */
109        public Formula compile(Cell cell, String source) throws FormulaCompilationException {
110                for (ExpressionCompiler compiler : compilers)
111                        if (source.charAt(0) == compiler.getStarter()) {
112                                Expression expression = compiler.compile(cell, source);
113                                return new Formula(cell, expression);
114                        }
115                return null;
116        }
117}