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.compiler;
022    
023    import java.io.IOException;
024    import java.io.InputStream;
025    import java.util.ArrayList;
026    import java.util.List;
027    import java.util.Properties;
028    
029    import csheets.CleanSheets;
030    import csheets.core.Cell;
031    import csheets.core.formula.Expression;
032    import csheets.core.formula.Formula;
033    
034    /**
035     * A compiler that generates formulas from strings.
036     * @author Einar Pehrson
037     */
038    public 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    }