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.ArrayList;
018    import java.util.List;
019    
020    /**
021     * This class represents a node of the parse tree. Each node has a category and an annotation
022     * object that are carried over from the edge in the chart parser and originate from the respective
023     * grammar rule. Additionally, each parse node has start and end positions denoting the covered
024     * part of the input text.
025     * 
026     * @author Tobias Kuhn
027     */
028    public class ParseTreeNode {
029            
030            private final Category category;
031            private final int startPos;
032            private final int endPos;
033            private final Annotation annotation;
034            private final List<ParseTreeNode> children = new ArrayList<ParseTreeNode>();
035            
036            /**
037             * Creates a new parse tree node out of the given edge.
038             * 
039             * @param edge The edge.
040             */
041            ParseTreeNode(Edge edge) {
042                    this.category = edge.getHead();
043                    this.startPos = edge.getStartPos();
044                    this.endPos = edge.getEndPos();
045                    this.annotation = edge.getAnnotation();
046                    int pos = edge.getStartPos();
047                    for (int i = 0 ; i < edge.getBody().length ; i++) {
048                            Edge e = edge.getLinks().get(i);
049                            if (e != null) {
050                                    try {
051                                            e.getHead().unify(edge.getBody()[i]);
052                                            children.add(new ParseTreeNode(e));
053                                    } catch (UnificationFailedException ex) {
054                                            throw new RuntimeException("Unexpected unification error", ex);
055                                    }
056                                    pos = e.getEndPos();
057                            } else {
058                                    children.add(new ParseTreeNode(edge.getBody()[i], pos));
059                            }
060                    }
061            }
062            
063            /**
064             * Creates a new parse tree node (without children) out of the given category.
065             * 
066             * @param category The category.
067             */
068            private ParseTreeNode(Category category, int pos) {
069                    this.category = category;
070                    this.startPos = pos;
071                    this.endPos = pos;
072                    this.annotation = new Annotation();
073            }
074            
075            /**
076             * Returns the category of this node.
077             * 
078             * @return The category.
079             */
080            public Category getCategory() {
081                    return category;
082            }
083            
084            /**
085             * Returns the start position. 0 is the position before the first token, 1 the position after
086             * the first token, 2 the position after the second token, and so on.
087             * 
088             * @return The start position.
089             */
090            public int getStartPos() {
091                    return startPos;
092            }
093            
094            /**
095             * Returns the end position. 0 is the position before the first token, 1 the position after
096             * the first token, 2 the position after the second token, and so on.
097             * 
098             * @return The end position.
099             */
100            public int getEndPos() {
101                    return endPos;
102            }
103            
104            /**
105             * Returns the annotation object of this node.
106             * 
107             * @return The annotation object.
108             */
109            public Annotation getAnnotation() {
110                    return annotation;
111            }
112            
113            /**
114             * Returns the annotation item for the given annotation item name.
115             * 
116             * @param name The name of the annotation item.
117             * @return The value of the annotation item.
118             */
119            public Object getAnnotationItem(String name) {
120                    return annotation.getItem(name);
121            }
122            
123            /**
124             * Returns the children of this node.
125             * 
126             * @return The children.
127             */
128            public List<ParseTreeNode> getChildren() {
129                    return children;
130            }
131            
132            /**
133             * Returns the child at the given position.
134             * 
135             * @param i The position.
136             * @return The child.
137             */
138            public ParseTreeNode getChild(int i) {
139                    return children.get(i);
140            }
141            
142            /**
143             * Returns the list of terminals that are descendants of this node.
144             * 
145             * @return The list of terminals.
146             */
147            public List<Terminal> getTerminals() {
148                    List<Terminal> terminals = new ArrayList<Terminal>();
149                    collectTerminals(terminals);
150                    return terminals;
151            }
152            
153            private void collectTerminals(List<Terminal> terminals) {
154                    if (category instanceof Terminal) {
155                            terminals.add((Terminal) category);
156                    } else {
157                            for (ParseTreeNode n : getChildren()) {
158                                    n.collectTerminals(terminals);
159                            }
160                    }
161            }
162    
163    }