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.List;
019    
020    /**
021     * This class represents a grammar rule. A grammar rule consists of a nonterminal category (called
022     * "head") and a sequence of categories (called "body"). Furthermore, a grammar rule can be
023     * scope-closing, which means that all scopes opened by its children are closed at the position
024     * after the last child category.
025     * 
026     * @author Tobias Kuhn
027     */
028    public class GrammarRule {
029            
030            private final Nonterminal head;
031            private final boolean scopeclosing;
032            private final Category[] body;
033            private final Annotation annotation;
034            
035            /**
036             * Creates a new grammar rule.
037             * 
038             * @param annotation The annotation object.
039             * @param head The head category.
040             * @param scopeclosing Defines whether the rule is scope-closing or not.
041             * @param body The category sequence of the body.
042             */
043            public GrammarRule(Annotation annotation, Nonterminal head, boolean scopeclosing, Category... body) {
044                    this.head = head;
045                    this.body = body;
046                    this.scopeclosing = scopeclosing;
047                    if (annotation == null) {
048                            this.annotation = new Annotation();
049                    } else {
050                            this.annotation = annotation;
051                    }
052            }
053            
054            /**
055             * Creates a new grammar rule.
056             * 
057             * @param head The head category.
058             * @param scopeclosing Defines whether the rule is scope-closing or not.
059             * @param body The category sequence of the body.
060             */
061            public GrammarRule(Nonterminal head, boolean scopeclosing, Category... body) {
062                    this(null, head, scopeclosing, body);
063            }
064            
065            /**
066             * Creates a new grammar rule that is not scope-closing.
067             * 
068             * @param head The head category.
069             * @param body The body category sequence.
070             */
071            public GrammarRule(Nonterminal head, Category... body) {
072                    this(null, head, false, body);
073            }
074            
075            /**
076             * Creates a new grammar rule.
077             * 
078             * @param annotation The annotation object.
079             * @param categories The first category of this list stands for the head category (it has to be
080             *     a Nonterminal object). The rest stands for the body categories.
081             * @param scopeclosing Defines whether the rule is scope-closing or not.
082             */
083            public GrammarRule(Annotation annotation, List<Category> categories, boolean scopeclosing) {
084                    this.scopeclosing = scopeclosing;
085                    this.head = (Nonterminal) categories.get(0);
086                    categories.remove(0);
087                    this.body = categories.toArray(new Category[0]);
088                    if (annotation == null) {
089                            this.annotation = new Annotation();
090                    } else {
091                            this.annotation = annotation;
092                    }
093            }
094            
095            /**
096             * Returns the head category of this grammar rule.
097             * 
098             * @return The head category.
099             */
100            public Nonterminal getHead() {
101                    return head;
102            }
103            
104            /**
105             * Returns the body category sequence of this grammar rule.
106             * 
107             * @return The body category sequence.
108             */
109            public Category[] getBody() {
110                    return body;
111            }
112            
113            /**
114             * Returns true if the body is empty. Such grammar rules are called "epsilon rules".
115             * 
116             * @return true if the body is empty.
117             */
118            public boolean hasEmptyBody() {
119                    return body.length == 0;
120            }
121            
122            /**
123             * Returns the first category of the body.
124             * 
125             * @return The first category of the body.
126             */
127            public Category getFirst() {
128                    return body[0];
129            }
130            
131            /**
132             * Returns true if the rule is scope-closing.
133             * 
134             * @return true if the rule is scope-closing.
135             */
136            public boolean isScopeClosing() {
137                    return scopeclosing;
138            }
139            
140            /**
141             * Returns the annotation object of this rule.
142             * 
143             * @return The annotation object.
144             */
145            public Annotation getAnnotation() {
146                    return annotation;
147            }
148            
149            /**
150             * Creates a deep copy of this rule.
151             * 
152             * @return A deep copy.
153             */
154            public GrammarRule deepCopy() {
155                    return deepCopy(new HashMap<Integer, StringObject>());
156            }
157            
158            /**
159             * Creates a deep copy of this rule using the given string objects. This method is
160             * usually called form another deepCopy-method.
161             * 
162             * @param stringObjs The string objects to be used.
163             * @return A deep copy.
164             */
165            GrammarRule deepCopy(HashMap<Integer, StringObject> stringObjs) {
166                    Nonterminal headC = (Nonterminal) head.deepCopy(stringObjs);
167                    Category[] bodyC = new Category[body.length];
168                    for (int i=0; i < body.length ; i++) {
169                            bodyC[i] = body[i].deepCopy(stringObjs);
170                    }
171                    Annotation annotationC = annotation.deepCopy(stringObjs);
172                    return new GrammarRule(annotationC, headC, scopeclosing, bodyC);
173            }
174            
175            public String toString() {
176                    String s = head + " ";
177                    if (scopeclosing) {
178                            s += "~>";
179                    } else {
180                            s += "=>";
181                    }
182                    for (Category c : body) {
183                            s += " " + c;
184                    }
185                    return s;
186            }
187    
188    }