001    // This file is part of AceWiki.
002    // Copyright 2008-2012, AceWiki developers.
003    // 
004    // AceWiki is free software: you can redistribute it and/or modify it under the terms of the GNU
005    // Lesser General Public License as published by the Free Software Foundation, either version 3 of
006    // the License, or (at your option) any later version.
007    // 
008    // AceWiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009    // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
010    // Lesser General Public License for more details.
011    // 
012    // You should have received a copy of the GNU Lesser General Public License along with AceWiki. If
013    // not, see http://www.gnu.org/licenses/.
014    
015    package ch.uzh.ifi.attempto.chartparser;
016    
017    import java.util.HashMap;
018    import java.util.HashSet;
019    import java.util.Map;
020    import java.util.Set;
021    
022    import ch.uzh.ifi.attempto.base.NextTokenOptions;
023    
024    /**
025     * This class represents a set of options that describe how a partial text can be continued
026     * according to a given grammar, and contains specific code for its use in the chart parser.
027     * 
028     * @author Tobias Kuhn
029     */
030    public class CPNextTokenOptions implements NextTokenOptions {
031            
032            private Set<CPAbstractOption> aOptions;
033            private Set<CPConcreteOption> cOptions;
034            private Map<String,Set<CPAbstractOption>> categoryMap;
035            private Set<String> tokens;
036            
037            /**
038             * Generates a new object with the given abstract and concrete options.
039             * 
040             * @param aOptions The set of abstract options.
041             * @param cOptions The set of concrete options.
042             */
043            CPNextTokenOptions(Set<CPAbstractOption> aOptions, Set<CPConcreteOption> cOptions) {
044                    this.aOptions = aOptions;
045                    this.cOptions = cOptions;
046            }
047            
048            public Set<CPAbstractOption> getAbstractOptions() {
049                    return aOptions;
050            }
051            
052            /**
053             * Returns the abstract options that have a pre-terminal category with the specified name.
054             * 
055             * @param categoryName The name of the category.
056             * @return The set of abstract options with the respective category name.
057             */
058            public Set<CPAbstractOption> getAbstractOptions(String categoryName) {
059                    createCategoryCache();
060                    Set<CPAbstractOption> s = categoryMap.get(categoryName);
061                    if (s == null) {
062                            s = new HashSet<CPAbstractOption>();
063                            categoryMap.put(categoryName, s);
064                    }
065                    return s;
066            }
067            
068            public Set<CPConcreteOption> getConcreteOptions() {
069                    return cOptions;
070            }
071            
072            public boolean containsToken(String token) {
073                    createTokenCache();
074                    return tokens.contains(token);
075            }
076            
077            public boolean containsCategory(String categoryName) {
078                    createCategoryCache();
079                    return categoryMap.containsKey(categoryName);
080            }
081            
082            /**
083             * Returns true if the given pre-terminal category represents a possible next token.
084             * 
085             * @param c The pre-terminal category.
086             * @return true if it represents a possible next token.
087             */
088            public boolean containsCategory(Preterminal c) {
089                    createCategoryCache();
090                    if (!categoryMap.containsKey(c.getName())) return false;
091                    for (CPAbstractOption o : getAbstractOptions(c.getName())) {
092                            if (o.isFulfilledBy(c)) {
093                                    return true;
094                            }
095                    }
096                    return false;
097            }
098            
099            private void createTokenCache() {
100                    if (tokens != null) return;
101                    
102                    tokens = new HashSet<String>();
103                    for (CPConcreteOption o : cOptions) {
104                            tokens.add(o.getWord());
105                    }
106            }
107            
108            private void createCategoryCache() {
109                    if (categoryMap != null) return;
110                    
111                    categoryMap = new HashMap<String, Set<CPAbstractOption>>();
112                    for (CPAbstractOption o : aOptions) {
113                            if (o.getCategory() instanceof Preterminal) {
114                                    String n = o.getCategory().getName();
115                                    Set<CPAbstractOption> s = categoryMap.get(n);
116                                    if (s == null) {
117                                            s = new HashSet<CPAbstractOption>();
118                                            categoryMap.put(n, s);
119                                    }
120                                    s.add(o);
121                            }
122                    }
123            }
124    
125    }